Spring profiles allow you to run the same application with different configurations depending on the environment, such as development, testing, staging, or production.
For example, your development environment may use an in-memory database, while production uses MySQL or PostgreSQL.
1. What Is a Spring Profile?
A profile is a named set of configuration settings that Spring loads only when that profile is active.
Common profile names include:
devteststagingprod
Profiles help you avoid hardcoding environment-specific values directly in your application code.
2. Creating Profile-Specific Configuration Files
In a Spring Boot application, you usually define configuration in application.properties or application.yml.
You can create separate files for each environment:
src/main/resources/
├── application.properties
├── application-dev.properties
├── application-test.properties
└── application-prod.properties
Spring Boot automatically loads the file that matches the active profile.
3. Example Using application.properties
The default configuration file:
spring.application.name=my-spring-app
server.port=8080
Development profile:
spring.datasource.url=jdbc:h2:mem:devdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
logging.level.org.springframework=DEBUG
Production profile:
spring.datasource.url=jdbc:postgresql://prod-db-server:5432/appdb
spring.datasource.username=app_user
spring.datasource.password=${DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=validate
logging.level.org.springframework=WARN
Here:
application-dev.propertiesis used for development.application-prod.propertiesis used for production.${DB_PASSWORD}reads the value from an environment variable.
4. Example Using YAML
You can also use application.yml:
spring:
application:
name: my-spring-app
server:
port: 8080
Profile-specific YAML files can be created like this:
application-dev.yml
application-prod.yml
Example application-dev.yml:
spring:
datasource:
url: jdbc:h2:mem:devdb
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
logging:
level:
org.springframework: DEBUG
Example application-prod.yml:
spring:
datasource:
url: jdbc:postgresql://prod-db-server:5432/appdb
username: app_user
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
logging:
level:
org.springframework: WARN
5. Activating a Profile
There are several ways to activate a Spring profile.
Option 1: In application.properties
spring.profiles.active=dev
This is simple, but usually best for local development only.
Avoid committing spring.profiles.active=prod into shared configuration unless you are sure it is appropriate.
Option 2: From the Command Line
java -jar my-spring-app.jar --spring.profiles.active=prod
You can also pass it as a JVM system property:
java -Dspring.profiles.active=prod -jar my-spring-app.jar
Option 3: Using an Environment Variable
On macOS/Linux:
export SPRING_PROFILES_ACTIVE=prod
java -jar my-spring-app.jar
On Windows PowerShell:
$env:SPRING_PROFILES_ACTIVE="prod"
java -jar my-spring-app.jar
This is commonly used in Docker, Kubernetes, CI/CD pipelines, and cloud platforms.
6. Using Profiles with Beans
Profiles are not limited to configuration files. You can also create beans that only exist in certain environments.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public String devDatabaseMessage() {
return "Using development database";
}
@Bean
@Profile("prod")
public String prodDatabaseMessage() {
return "Using production database";
}
}
When the dev profile is active, only the devDatabaseMessage bean is registered. When the prod profile is active, only the prodDatabaseMessage bean is registered.
7. Using Profiles on Classes
You can also place @Profile on an entire configuration class or component:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@Profile("dev")
public class DevConfiguration {
// Beans here are loaded only when the dev profile is active
}
Another example:
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@Service
@Profile("test")
public class MockEmailService implements EmailService {
@Override
public void sendEmail(String to, String subject, String body) {
System.out.println("Pretending to send email in test environment");
}
}
A production implementation could look like this:
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@Service
@Profile("prod")
public class SmtpEmailService implements EmailService {
@Override
public void sendEmail(String to, String subject, String body) {
// Send real email using SMTP provider
}
}
8. Using Multiple Profiles
Spring allows more than one profile to be active at the same time.
java -jar my-spring-app.jar --spring.profiles.active=prod,metrics
You can then annotate beans like this:
@Profile("metrics")
@Bean
public MeterRegistryCustomizer<?> metricsCustomizer() {
return registry -> registry.config().commonTags("application", "my-spring-app");
}
9. Setting a Default Profile
If no profile is active, Spring uses the default profile.
You can define a default profile like this:
spring.profiles.default=dev
Or in YAML:
spring:
profiles:
default: dev
This means the application uses dev settings unless another profile is explicitly activated.
10. Profile Expressions
The @Profile annotation also supports expressions.
@Profile("dev | test")
This bean is active when either dev or test is active.
@Profile("!prod")
This bean is active when the prod profile is not active.
@Profile("prod & metrics")
This bean is active only when both prod and metrics are active.
11. Using Profiles in Tests
For tests, you can activate a profile with @ActiveProfiles.
import org.junit.jupiter.api.Test;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@ActiveProfiles("test")
class UserServiceTest {
@Test
void shouldLoadApplicationContext() {
// test code here
}
}
Then create:
src/test/resources/application-test.properties
Example:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
12. Common Use Case: Database Per Environment
Development:
spring.datasource.url=jdbc:h2:mem:devdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
Testing:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
Production:
spring.datasource.url=jdbc:postgresql://localhost:5432/proddb
spring.datasource.username=prod_user
spring.datasource.password=${DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=validate
A good rule is:
spring.jpa.hibernate.ddl-auto=validate
for production, instead of create, create-drop, or update.
13. Best Practices
- Use profiles for environment-specific configuration.
- Keep secrets out of committed files.
- Use environment variables for passwords, tokens, and API keys.
- Prefer
prodconfiguration to be strict and safe. - Use
validateor a migration tool like Flyway/Liquibase in production. - Avoid hardcoding
spring.profiles.active=prodin source control. - Use
@Profileonly when bean behavior really differs by environment. - Prefer external configuration for values like URLs, credentials, and feature flags.
Summary
Spring profiles let you run the same application with different settings for each environment.
Typical setup:
application.properties
application-dev.properties
application-test.properties
application-prod.properties
Activate a profile like this:
java -jar my-spring-app.jar --spring.profiles.active=dev
Use @Profile when certain beans should only be available in specific environments:
@Profile("prod")
@Bean
public SomeService productionService() {
return new SomeService();
}
In short, profiles make your Spring application easier to configure, safer to deploy, and cleaner to maintain across different environments.
