Spring Boot Profiles Tutorial

Watch on YouTube

Spring Boot Profiles

Core idea: A Spring profile selects a group of beans and configuration values for a particular runtime environment. Keep profile files environment-specific, activate exactly one intended deployment configuration, and store secrets outside source control.

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?

EnvironmentTypical configurationPurpose
devLocal database, debug logging, developer toolsFast feedback during development
testIsolated database, test doubles, deterministic settingsRepeatable automated tests
stagingProduction-like services with safe test credentialsRelease verification
prodManaged database, external services, restricted logsReliable 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
Security rule: Never commit database passwords, API keys, or private certificates to a profile file. Use environment variables, a secret manager, or your deployment platform's secret store.

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

  1. Keep shared, non-secret defaults in application.properties.
  2. Use application-{profile}.properties or YAML for environment differences.
  3. Activate profiles from deployment configuration rather than hardcoding production.
  4. Keep secrets in environment variables or a secret manager.
  5. Use validate or migrations instead of destructive schema settings in production.
  6. Test every supported profile during CI/CD.
  7. Document the expected active profile for each deployment target.
  8. 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.

Back to Spring Boot Course

Continue learning