How do I use profiles for different Spring environments?

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:

  • dev
  • test
  • staging
  • prod

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.properties is used for development.
  • application-prod.properties is 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 prod configuration to be strict and safe.
  • Use validate or a migration tool like Flyway/Liquibase in production.
  • Avoid hardcoding spring.profiles.active=prod in source control.
  • Use @Profile only 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.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.