Configuration & Profiles
Spring Boot’s externalized configuration lets one build artifact run unchanged across environments. Settings live outside the code, in YAML, environment variables, or command-line arguments, and Spring binds them to typed objects.
application.yml
YAML is the idiomatic format for hierarchical configuration. Spring Boot reads application.yml from the classpath automatically.
server:
port: 8080
app:
name: Devcraftly Shop
feature-flags:
new-checkout: true
retry:
max-attempts: 3
backoff-ms: 500
Reading single values with @Value
@Value injects an individual property using placeholder syntax, with an optional default after the colon.
@Service
public class GreetingService {
@Value("${app.name}")
private String appName;
@Value("${app.timeout:30}") // default 30 if missing
private int timeoutSeconds;
}
Note:
@Valueis fine for one or two properties, but it offers no type safety for groups and scatters config keys across your codebase.
Typed binding with @ConfigurationProperties
For related settings, bind a whole tree to a typed class. This gives you validation, IDE completion, and a single source of truth.
@Configuration
@ConfigurationProperties(prefix = "app.retry")
@Validated
public class RetryProperties {
@Min(1)
private int maxAttempts;
private long backoffMs;
// getters and setters
}
Inject it like any other bean:
@Service
public class OrderClient {
private final RetryProperties retry;
public OrderClient(RetryProperties retry) {
this.retry = retry;
}
}
Tip: Prefer
@ConfigurationPropertiesover multiple@Valueannotations. It is type-safe, supports relaxed binding (max-attemptsmaps tomaxAttempts), and validates at startup.
Spring Profiles
Profiles let you maintain environment-specific configuration. Create application-<profile>.yml files that override the base application.yml.
# application-dev.yml
spring:
datasource:
url: jdbc:h2:mem:devdb
logging:
level:
org.hibernate.SQL: DEBUG
# application-prod.yml
spring:
datasource:
url: jdbc:postgresql://db:5432/shop
logging:
level:
root: WARN
Activate a profile at runtime:
java -jar app.jar --spring.profiles.active=prod
# or via environment variable
export SPRING_PROFILES_ACTIVE=prod
You can also restrict beans to specific profiles:
@Bean
@Profile("dev")
public CommandLineRunner sampleData(ProductRepository repo) {
return args -> repo.save(new Product("Demo", BigDecimal.TEN));
}
Externalized config and precedence
Spring Boot merges configuration from many sources in a defined order. Higher-priority sources override lower ones.
| Priority | Source |
|---|---|
| Highest | Command-line arguments |
SPRING_APPLICATION_JSON | |
| OS environment variables | |
Profile-specific application-<profile>.yml | |
| Lowest | Base application.yml |
This precedence is what makes the same JAR portable: defaults ship in YAML, and each environment overrides only what differs.
Environment variables
Spring’s relaxed binding maps environment variables to properties: uppercase the key and replace dots with underscores. So app.name becomes APP_NAME.
export SERVER_PORT=9090
export SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/shop
java -jar app.jar
This convention is essential for containerized and cloud deployments, where secrets and connection strings arrive as environment variables rather than files.
Warning: Never commit secrets (passwords, API keys) to
application.yml. Inject them through environment variables or a secrets manager, and keep only safe defaults in version control.
Best Practices
- Use
@ConfigurationPropertiesfor grouped settings; reserve@Valuefor one-off values. - Keep one base
application.ymlplus thin profile-specific overrides, never duplicate full configs. - Externalize all environment-specific and sensitive values through environment variables.
- Validate configuration at startup with
@Validatedto fail fast on misconfiguration. - Activate profiles explicitly per environment; avoid relying on a default profile in production.
- Document required properties so operators know exactly what each environment must supply.