A Complete Guide to Multi-Environment Configuration in Spring Boot
In real-world development and deployment, a single project often needs to run in multiple environments (e.g., local, dev, staging, production).
Spring Boot provides a powerful mechanism for environment-based configuration, allowing us to automatically load different settings based on runtime environment variables.
This article walks through how to design a clean and maintainable multi-environment configuration structure step by step.
1. Design Goal
The following behavior is desired:
Environment Variable $ENV |
Configuration File Used |
---|---|
Not Set / None | application-local.yml |
production |
application-production.yml |
staging |
application-staging.yml |
dev |
application-dev.yml |
2. Recommended Project Structure
src/
└── main/
└── resources/
├── application.yml
├── application-local.yml
├── application-dev.yml
├── application-staging.yml
└── application-production.yml
3. Main Configuration: application.yml
In the main configuration, define the default profile as ${ENV:local}
:
spring:
profiles:
active: ${ENV:local} # Default to local if ENV is not set
ENV
is a system environment variable. ${ENV:local}
means if it’s not set, the default profile is local
.
4. Example Configuration Files
application-local.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/app_local
username: root
password: root
application-production.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://prod-db:3306/app_prod
username: prod_user
password: ${DB_PASSWORD}
application-staging.yml
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://staging-db:3306/app_staging
username: staging_user
password: staging_pwd
5. Switching Environments at Runtime
Option 1: Using Environment Variable
export ENV=production
java -jar app.jar
Or simply:
ENV=production java -jar app.jar
Option 2: Using Spring Boot Property
java -jar app.jar --spring.profiles.active=production
6. Reading the Active Profile in Code
If you need to dynamically read the active profile inside the application:
import org.springframework.core.env.Environment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class EnvChecker {
@Autowired
private Environment env;
public void printActiveProfile() {
String[] profiles = env.getActiveProfiles();
if (profiles.length == 0) {
System.out.println("No active profile set, using default: local");
} else {
System.out.println("Active profile: " + String.join(", ", profiles));
}
}
}
7. Loading Different Beans by Profile (Optional)
You can use @Profile
to load environment-specific beans:
@Configuration
@Profile("production")
public class ProductionConfig {
@Bean
public MyService myService() {
return new ProdMyService();
}
}
@Configuration
@Profile("local")
public class LocalConfig {
@Bean
public MyService myService() {
return new LocalMyService();
}
}
8. Packaging Strategy: One JAR for All Environments
Build Phase
When executing:
mvn clean package -DskipTests
or
./gradlew build
Spring Boot includes all configuration files (application*.yml
) in the JAR package.
At this stage, ${ENV}
is not parsed and no profile is activated.
Resulting structure inside the JAR:
BOOT-INF/classes/
├── application.yml
├── application-local.yml
├── application-production.yml
├── application-staging.yml
└── application-dev.yml
Runtime Phase
The environment variable determines which configuration file to load:
export ENV=production
java -jar app.jar
The same JAR can run in different environments without rebuilding.
9. Docker Example
Dockerfile
:
FROM eclipse-temurin:17-jdk
WORKDIR /app
COPY target/app.jar .
ENV ENV=production
ENTRYPOINT ["java", "-jar", "app.jar"]
Override the environment variable at runtime if needed:
docker run -e ENV=staging myapp:latest
10. Deployment Strategy Recommendation
Environment | Deployment Method | ENV Variable |
---|---|---|
Local | Manual Run | ENV=local |
Dev | CI/CD Pipeline | ENV=dev |
Staging | CI/CD Pipeline | ENV=staging |
Production | CI/CD / Docker | ENV=production |
Summary
Feature | Description |
---|---|
Default Profile | Defined in application.yml as ${ENV:local} |
Multi-Environment Files | application-{profile}.yml |
Packaging | One JAR for all environments |
Runtime Switching | ENV=production java -jar app.jar |
Reading Active Profile | Environment.getActiveProfiles() |
Environment-Specific Beans | Use @Profile("xxx") |
Key Takeaway:
Spring Boot’s profile mechanism allows one universal build that can adapt to any environment simply by setting an environment variable — clean, consistent, and deployment-friendly.