How to Use Spring's @Profile Annotation for Flexible Configurations
The @Profile annotation in Spring allows you to segregate configurations to be available only in specific environments. If you mark a @Component (and its specializations) or any @Configuration or @Bean with the @Profile annotation, it will make them available only if the profile specified is active. You can set the profile using application.properties by using the spring.profiles.active property, or by specifying it in the command line when running the application. You can also use the spring.profiles.include property to add and combine more configuration profiles. Let’s explore some examples. Using profiles to separate environments In your application, you may have a database connection, but you need to deal with new features and test them in a separate environment. You need a validation environment before shipping your new feature to production. We can call this environment dev. And for the stable things that are running for all users of your application, you have a prod environment. Each environment has its own database. You can use profiles to set up your application pointing to the right environment. In this case, it will point to the right data source for the environment, but you can separate many other things if needed. So you can have a bean data source for the dev profile that is pointing to the dev database: import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource; @Configuration @Profile("dev") public class DevDataSourceConfig { @Bean public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setUrl("jdbc:h2:mem:devdb"); dataSource.setUsername("devuser"); dataSource.setPassword("devpass"); return dataSource; } } And another bean configuration for the prod profile is pointing to the production data source: import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource; @Configuration @Profile("prod") public class ProdDataSourceConfig { @Bean public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setUrl("jdbc:mysql://prodserver:3306/proddb"); dataSource.setUsername("produser"); dataSource.setPassword("prodpass"); return dataSource; } } (In the above code, I created a dummy class called BasicDataSource, which implements DataSource just to exemplify.) When you run your application without setting a profile, this log will be shown, telling that Spring is using the default profile: 2024-07-17T21:50:05.329-03:00 INFO 18568 --- [ main] com.spring.mastery.MasteryApplication : No active profile set, falling back to 1 default profile: "default" You can set the profile in the application.properties like this: spring.profiles.active=dev This log will show up: 2024-07-17T21:52:03.996-03:00 INFO 8240 --- [ main] com.spring.mastery.MasteryApplication : The following 1 profile is active: "dev" Spring will load the data source connection to the dev environment. You can set the profile in the command line: Using VM arguments: java -jar -Dspring.profiles.active=prod application.jar Or you can use program arguments: java -jar application.jar --spring.profiles.active=prod Now, when running your application, you choose the profile that the scenario needs. Combining Profiles Another interesting thing you could do is combine two different profiles. Let’s suppose that you have to do a test, and in this test, you want to load up the real cache manager bean that is used by your application and combine it with the test database. In this case, we are going to call the profile that holds the cache manager as common and the test profile that has the data source configuration for the test database. In your properties, you can set up the active environment as a test, and include the other profiles that you need. Like this in application.properties: spring.profiles.active=test spring.profiles.include=common So your Cache Manager is configured as the Common Profile: import org.springframework.cache.CacheManager; import org.springframework.cache.concurrent.ConcurrentMapCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @Configuration @Profile("common") public class CommonConfig { @Bean public CacheManager cacheManager() { log.info("Loading cache manager from common profile"); return new Concurre

The @Profile
annotation in Spring allows you to segregate configurations to be available only in specific environments.
If you mark a @Component
(and its specializations) or any @Configuration
or @Bean
with the @Profile
annotation, it will make them available only if the profile specified is active.
You can set the profile using application.properties
by using the spring.profiles.active
property, or by specifying it in the command line when running the application.
You can also use the spring.profiles.include
property to add and combine more configuration profiles.
Let’s explore some examples.
Using profiles to separate environments
In your application, you may have a database connection, but you need to deal with new features and test them in a separate environment. You need a validation environment before shipping your new feature to production. We can call this environment dev
.
And for the stable things that are running for all users of your application, you have a prod
environment.
Each environment has its own database. You can use profiles to set up your application pointing to the right environment. In this case, it will point to the right data source for the environment, but you can separate many other things if needed.
So you can have a bean data source for the dev
profile that is pointing to the dev
database:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
@Configuration
@Profile("dev")
public class DevDataSourceConfig {
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:h2:mem:devdb");
dataSource.setUsername("devuser");
dataSource.setPassword("devpass");
return dataSource;
}
}
And another bean configuration for the prod
profile is pointing to the production data source:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
@Configuration
@Profile("prod")
public class ProdDataSourceConfig {
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://prodserver:3306/proddb");
dataSource.setUsername("produser");
dataSource.setPassword("prodpass");
return dataSource;
}
}
(In the above code, I created a dummy class called BasicDataSource
, which implements DataSource
just to exemplify.)
When you run your application without setting a profile, this log will be shown, telling that Spring is using the default profile:
2024-07-17T21:50:05.329-03:00 INFO 18568 --- [ main] com.spring.mastery.MasteryApplication : No active profile set, falling back to 1 default profile: "default"
You can set the profile in the application.properties
like this:
spring.profiles.active=dev
This log will show up:
2024-07-17T21:52:03.996-03:00 INFO 8240 --- [ main] com.spring.mastery.MasteryApplication : The following 1 profile is active: "dev"
Spring will load the data source connection to the dev environment.
You can set the profile in the command line:
Using VM arguments:
java -jar -Dspring.profiles.active=prod application.jar
Or you can use program arguments:
java -jar application.jar --spring.profiles.active=prod
Now, when running your application, you choose the profile that the scenario needs.
Combining Profiles
Another interesting thing you could do is combine two different profiles.
Let’s suppose that you have to do a test, and in this test, you want to load up the real cache manager bean that is used by your application and combine it with the test database.
In this case, we are going to call the profile that holds the cache manager as common
and the test profile that has the data source configuration for the test database.
In your properties, you can set up the active environment as a test, and include the other profiles that you need.
Like this in application.properties
:
spring.profiles.active=test
spring.profiles.include=common
So your Cache Manager is configured as the Common Profile:
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@Profile("common")
public class CommonConfig {
@Bean
public CacheManager cacheManager() {
log.info("Loading cache manager from common profile");
return new ConcurrentMapCacheManager("entities");
}
}
Your Test Profile points to the test data source:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
@Configuration
@Profile("test")
public class TestDataSourceConfig {
@Bean
public DataSource dataSource() {
log.info("Loading data source bean from the test profile");
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:h2:mem:testdb");
dataSource.setUsername("testuser");
dataSource.setPassword("testpass");
return dataSource;
}
}
When you run your application, you will have the beans from both profiles available and set.
A log line like this will show up:
The following 2 profiles are active: "common", "test"
In this blog post, we did this only with @Bean
and @Configuration
classes, but you could use this for all @Component
and specializations too!
When used in a @Configuration
class, it will set all the @Beans
in it to the specific profile.
Now you’ve learned how to use the @Profile
annotation in your project. Have you seen this annotation before? Can you think of more usages for this annotation? Share your thoughts with me in the comments or on social media.
If you like this topic, make sure to follow me. In the following days, I’ll be explaining more about Spring annotations! Stay tuned!