Spring Boot Profiles Tutorial
Watch on YouTubeSpring Boot Profiles
Spring Boot profiles are useful throughout the software development lifecycle. Development may use a local database and verbose logs, testing may use isolated infrastructure, staging may mirror production safely, and production should use managed services with restricted logging.
Why use Spring Boot profiles?
| Environment | Typical configuration | Purpose |
|---|---|---|
dev | Local database, debug logging, developer tools | Fast feedback during development |
test | Isolated database, test doubles, deterministic settings | Repeatable automated tests |
staging | Production-like services with safe test credentials | Release verification |
prod | Managed database, external services, restricted logs | Reliable production operation |
- Keep environment-specific configuration separate from application code.
- Switch deployment behavior without rebuilding the application.
- Reduce the risk of sending development settings to production.
- Make testing against different infrastructure explicit and repeatable.
Create a demo project
Generate a Maven project with Spring Initializr and select Spring Web, Spring Data JPA, MySQL Driver, Lombok, and Spring Boot Test. Spring Boot manages compatible dependency versions through its dependency management, so avoid hardcoding versions unless you have a specific compatibility requirement.
For a production application, Spring Boot's default HikariCP connection pool is usually sufficient. Add Apache Commons DBCP2 only when the application has a deliberate reason to use it.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Open Spring Initializr and import the generated project into IntelliJ IDEA or your preferred IDE.
Create profile-specific property files
Place shared defaults in application.properties, then add files named application-{profile}.properties. Spring Boot loads the matching file when that profile is active.
src/main/resources/
├── application.properties
├── application-dev.properties
├── application-test.properties
├── application-staging.properties
└── application-prod.properties
Shared application.properties
spring.application.name=order-service
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.format_sql=true
application-dev.properties
server.port=9090
spring.datasource.url=${DEV_DB_URL:jdbc:mysql://localhost:3306/dev}
spring.datasource.username=${DEV_DB_USERNAME:root}
spring.datasource.password=${DEV_DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=update
logging.level.com.javacodeex.orders=DEBUG
application-test.properties
server.port=9091
spring.datasource.url=${TEST_DB_URL:jdbc:mysql://localhost:3306/test}
spring.datasource.username=${TEST_DB_USERNAME:root}
spring.datasource.password=${TEST_DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=create-drop
logging.level.com.javacodeex.orders=INFO
application-staging.properties
server.port=8080
spring.jpa.hibernate.ddl-auto=validate
logging.level.root=INFO
application-prod.properties
server.port=8080
spring.datasource.url=${PROD_DB_URL}
spring.datasource.username=${PROD_DB_USERNAME}
spring.datasource.password=${PROD_DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=validate
logging.level.root=WARN
Enable profile-specific beans
Use @Profile when a bean should exist only for a named environment. The configuration below demonstrates separate data sources while reusing externalized properties.
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Bean
@Profile({"dev", "test", "staging", "prod"})
DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
In most Spring Boot applications, prefer Boot's auto-configured DataSource and use profile files only for the values that differ. Create separate beans with @Profile when the implementation itself changes, such as a real payment client versus a test double.
Activate a profile
Choose one activation method for each deployment. Command-line arguments and environment variables are convenient for containers and CI/CD because they do not require editing the packaged application.
In application.properties
spring.profiles.active=dev
Use this mainly for local defaults. Avoid packaging prod as the default active profile.
With a command-line argument
java -jar order-service.jar --spring.profiles.active=prod
With an environment variable
export SPRING_PROFILES_ACTIVE=test
java -jar order-service.jar
With a JVM system property
java -Dspring.profiles.active=prod -jar order-service.jar
With multiple profiles
java -jar order-service.jar --spring.profiles.active=prod,metrics
When multiple profiles are active, Spring Boot combines their configuration. Keep overlapping keys intentional and document which profile should win when the same property appears more than once.
Use profile groups for related settings
Profile groups let one logical profile activate several supporting profiles. This is useful when production needs a group of observability or infrastructure settings.
spring.profiles.group.production[0]=prod
spring.profiles.group.production[1]=metrics
spring.profiles.group.production[2]=external-services
java -jar order-service.jar --spring.profiles.active=production
Use profiles in tests
Activate a test profile for a test class or test suite. Keep test credentials and test database settings isolated from developer and production configuration.
import org.springframework.test.context.ActiveProfiles;
@SpringBootTest
@ActiveProfiles("test")
class OrderServiceIntegrationTest {
// Tests use application-test.properties.
}
Spring Boot profile best practices
- Keep shared, non-secret defaults in
application.properties. - Use
application-{profile}.propertiesor YAML for environment differences. - Activate profiles from deployment configuration rather than hardcoding production.
- Keep secrets in environment variables or a secret manager.
- Use
validateor migrations instead of destructive schema settings in production. - Test every supported profile during CI/CD.
- Document the expected active profile for each deployment target.
- Do not use profiles as a substitute for feature flags or tenant configuration.
Spring Boot Profiles FAQs
What is the default Spring Boot profile?
If no profile is active, Spring Boot uses the default configuration and the default profile behavior. You can configure a fallback with spring.profiles.default.
Should production passwords be stored in application-prod.properties?
No. Keep the property keys in the profile file if useful, but inject secret values through environment variables, a secret manager, or platform secrets.
Can multiple Spring profiles be active?
Yes. Set a comma-separated list such as prod,metrics. Keep overlapping values deliberate and test the final merged configuration.
Continue learning
