Externalized Configuration and Properties
Definition
Externalised configuration means settings live outside your code, in property files, environment variables or command-line arguments, with a clear order of which wins. @ConfigurationProperties binds related settings into one typed object.
Why it exists
Hard-coded settings force a new build for each environment, and secrets in code leak. Moving settings out lets the same build run anywhere.
How it works
Precedence (highest wins), simplified
- Command-line arguments (
--server.port=9000) SPRING_APPLICATION_JSONand Java system properties (-Dserver.port=9000)- OS environment variables (
SERVER_PORT=9000) - Profile-specific files outside the JAR, then inside:
application-prod.yml application.yml/application.propertiesoutside the JAR, then inside@PropertySourceandSpringApplication.setDefaultProperties
Practical consequence: in Kubernetes you set environment variables or mount a config file and never rebuild the image.
Relaxed binding maps server.port, SERVER_PORT and serverPort to the same property. Environment variables use upper-case with underscores: SPRING_DATASOURCE_URL is spring.datasource.url.
Profiles
# application.yml
spring:
application:
name: order-service
greeting:
message: Hello
---
spring:
config:
activate:
on-profile: prod
greeting:
message: Welcome
Activate with --spring.profiles.active=prod or SPRING_PROFILES_ACTIVE=prod. A bean can be restricted with @Profile("prod").
Example code
@Value versus @ConfigurationProperties
@Value("${greeting.message}") is fine for one-off values. For groups of settings prefer @ConfigurationProperties: it is type-safe, supports nested objects, lists and durations, validates, and generates IDE metadata.
A modern, immutable form uses a Java record (constructor binding is automatic for records):
@ConfigurationProperties(prefix = "payment")
@Validated
public record PaymentProperties(
@NotBlank String gatewayUrl,
@DefaultValue("3") @Min(1) @Max(10) int maxRetries,
@DefaultValue("5s") Duration timeout,
List<String> allowedCurrencies) {
}
Enable it either with @EnableConfigurationProperties(PaymentProperties.class) or @ConfigurationPropertiesScan on the application class.
payment:
gateway-url: https://pay.example.com
max-retries: 5
timeout: 2s
allowed-currencies: [INR, USD]
If gateway-url is missing or blank, the application fails at startup with a clear message, which is exactly what you want from configuration errors.
Usage:
@Service
class PaymentClient {
private final PaymentProperties props;
PaymentClient(PaymentProperties props) {
this.props = props;
}
Duration timeout() {
return props.timeout();
}
}
System design considerations
- Validate properties at startup so bad configuration fails fast
- Use the platform secret store and never log secrets
- Keep configuration changes reviewable and versioned
Secrets
Never commit secrets in application.yml. Supply them from environment variables, Kubernetes secrets, or a vault (HashiCorp Vault, cloud secret managers, Spring Cloud Config with encryption). Boot also supports configtree: to read each file in a mounted directory as a property.
When to use it, and when not
Use it when
- Settings differ per environment or per deployment
- You group related settings and want validation at startup
- You inject secrets from the platform
Think twice when
- You commit secrets or environment-specific values to the repository
- You scatter @Value strings across many classes
- A change would require a code deploy for what is really configuration
Common mistakes
- Duplicate keys with different casing or format across properties and YAML.
- Forgetting that
@Profileon a bean andon-profilein a document are different mechanisms for different things. - Binding a
Listfrom environment variables: useMY_LIST_0,MY_LIST_1or a comma-separated value. - Using mutable properties classes with setters when records would make them immutable.
Interview questions
1. In what order does Spring Boot resolve properties?
Command-line args over system properties over environment variables over profile files over default application files over defaults in code. Outside-the-JAR files beat inside-the-JAR files.
2. @Value vs @ConfigurationProperties?
@Value injects single values with SpEL support but no relaxed binding for the expression key and no grouping. @ConfigurationProperties binds a whole prefix to a typed object with relaxed binding, validation and metadata.
3. How do you have different configuration per environment?
Profile-specific files or documents, activated by spring.profiles.active, plus environment variables for deployment-specific values and secrets.
4. How do you validate configuration?
Annotate the properties class with @Validated and put Jakarta constraints on fields. Binding fails at startup if they are violated.
5. How do you refresh configuration at runtime?
Plain Boot does not. With Spring Cloud, @RefreshScope beans re-bind when /actuator/refresh is called or a bus event arrives (see Config Server).
Check yourself
1Which source normally overrides application.yml?
2Why prefer @ConfigurationProperties for related settings?
3Where should production secrets live?
Key takeaways
- One artifact, many environments: change configuration, not code.
- Higher-priority sources override lower ones; env vars and CLI args win.
- Prefer validated
@ConfigurationPropertiesrecords over scattered@Value. - Keep secrets out of the repository.
Next: Actuator.
Next topicActuatorFinished this page? Track your progress (saved only in your browser).