Profiles in Spring Boot: Managing Multiple Environments

When developing an application, you often need different configurations for different environments. For example:

  • In development, you might want verbose logging and a local database.
  • In testing, you might use a mock service or in-memory database.
  • In production, you need optimized settings, security, and real services.

Managing these differences manually can be messy. This is where Profiles in Spring Boot come to the rescue.

In this guide, we’ll walk you through:

  • ✅ What are Spring Profiles?
  • ✅ How to create and structure environment-specific configurations
  • ✅ How to activate and switch between profiles
  • ✅ How to load profile-specific beans
  • ✅ Best practices and common pitfalls
Profiles in Spring Boot

✅ What Are Spring Profiles?

Spring Profiles allow developers to create logical groupings of beans and configurations which can be registered and activated conditionally. This means you can isolate your configurations and activate only the ones relevant for a specific environment.

For example:

  • Load application-dev.properties for development
  • Load application-prod.properties for production

With profiles, Spring Boot lets you:

  • Control which configuration files are loaded
  • Customize bean definitions per environment
  • Simplify deployment and reduce configuration errors

📁 Creating Environment-Specific Property Files

Spring Boot, by default, looks for a file named application.properties or application.yml. To use profiles, you create profile-specific files.

🔸 Using .properties



application.properties           # Shared/default config
application-dev.properties       # Development environment
application-test.properties      # Testing environment
application-prod.properties      # Production environment

Each of these files can contain different property values depending on the environment.

Example:

application-dev.properties


server.port=8081
spring.datasource.url=jdbc:h2:mem:devdb
logging.level.root=DEBUG

application-prod.properties



server.port=8080
spring.datasource.url=jdbc:postgresql://prod-db-server:5432/mydb
logging.level.root=ERROR

🔸 Using application.yml with Profiles


spring:
  profiles:
    active: dev

---
spring:
  profiles: dev
server:
  port: 8081
app:
  message: Hello from DEV!

---
spring:
  profiles: prod
server:
  port: 8080
app:
  message: Hello from PROD!

🚀 Activating a Profile

Spring Boot provides multiple ways to activate a profile.

✅ 1. In application.properties or application.yml



spring.profiles.active=dev

✅ 2. Via Command Line


java -jar your-app.jar --spring.profiles.active=prod

✅ 3. As an Environment Variable (e.g., in Docker or CI)


export SPRING_PROFILES_ACTIVE=test

✅ 4. JVM System Property (useful in IDEs)


-Dspring.profiles.active=prod

💡 Tip: Never hardcode production profiles inside the code. Use command-line or environment variables to control it externally.

🧠 Using @Profile to Load Beans Conditionally

Spring allows you to load specific beans only for a particular profile.

Example:



@Configuration
public class AppConfig {

    @Bean
    @Profile("dev")
    public DataSource devDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .build();
    }

    @Bean
    @Profile("prod")
    public DataSource prodDataSource() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setUrl("jdbc:postgresql://prod-db:5432/mydb");
        ds.setUsername("produser");
        ds.setPassword("securepass");
        return ds;
    }
}

With this setup:

  • If the active profile is dev, you get an H2 in-memory database.
  • If the active profile is prod, you connect to a production PostgreSQL database.

🧪 Sample Controller to Demonstrate Profiles

1. Add a Message in application-dev.properties


app.message=Running in DEV mode!

2. Add a Message in application-prod.properties


app.message=Running in PROD mode!

3. Use in a Controller


@RestController
public class ProfileController {

    @Value("${app.message}")
    private String message;

    @GetMapping("/profile-info")
    public String getProfileInfo() {
        return message;
    }
}

Output

  • If spring.profiles.active=dev, response will be:
    “Running in DEV mode!”
  • If spring.profiles.active=prod, response will be:
    “Running in PROD mode!”

⚠️ Common Pitfalls

🔸 Not setting any profile: If no active profile is defined, only application.properties is used. Spring won’t load any application-<profile>.properties files unless a profile is active.

🔸 Conflicting properties: If the same key exists in application.properties and a profile-specific file, the profile-specific value will override the default.

🔸 Forgetting to use @Profile: Even if the profile is active, beans without @Profile annotations will always be created.

✅ Best Practices

✅ Use profile-specific files to isolate configurations.
✅ Keep sensitive information like passwords out of source control—use environment variables or external config services.
✅ Set a default profile or provide fallback behavior.
✅ Document which profiles are supported and when to use them.

📌 Summary

FeatureBenefit
application-<profile>.propertiesCustomizes properties per environment
spring.profiles.activeLets you switch environments dynamically
@ProfileControls bean loading based on active profile
Multiple activation optionsFlexible for local, CI/CD, cloud

🎯 Final Thoughts

Spring Boot profiles provide an elegant and flexible way to manage configuration across different stages of application development. With just a bit of setup, you can easily avoid config-related errors and ensure your app behaves as expected in each environment.

“Environment-specific configuration is no longer a hassle with Spring Profiles.”

📘 External References