Skip to main content
Spring Framework · Topic 9 of 25

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​

  1. Command-line arguments (--server.port=9000)
  2. SPRING_APPLICATION_JSON and Java system properties (-Dserver.port=9000)
  3. OS environment variables (SERVER_PORT=9000)
  4. Profile-specific files outside the JAR, then inside: application-prod.yml
  5. application.yml / application.properties outside the JAR, then inside
  6. @PropertySource and SpringApplication.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 @Profile on a bean and on-profile in a document are different mechanisms for different things.
  • Binding a List from environment variables: use MY_LIST_0, MY_LIST_1 or 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​

Quick quiz3 questions

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 @ConfigurationProperties records over scattered @Value.
  • Keep secrets out of the repository.

Next: Actuator.

Next topicActuator

Finished this page? Track your progress (saved only in your browser).