Type-Safe Config with @ConfigurationProperties
Type-Safe Config with @ConfigurationProperties
In the previous lesson you saw how to read individual values with @Value. That approach works for one or two properties, but when a feature needs a dozen related settings — timeout, retry count, base URL, credentials — injecting each one separately produces scattered, hard-to-maintain code. Spring Boot solves this with @ConfigurationProperties: a mechanism that binds an entire group of properties to a single, strongly-typed Java class.
Why Prefer @ConfigurationProperties Over @Value
Consider injecting five mail-server settings with @Value:
Each annotation is fragile: a typo in the key compiles fine but throws at runtime. There is no IDE auto-complete across the group, no validation, and no single place to see all the settings together. @ConfigurationProperties fixes every one of these issues.
Basic Setup
First, declare a plain Java class annotated with @ConfigurationProperties and a common prefix. In Spring Boot 3 you also need to mark it with @Component (or register it via @EnableConfigurationProperties).
Then in application.properties (or application.yml):
timeout-ms, timeoutMs, TIMEOUT_MS, and timeout_ms all to the same field. You only need to be consistent within a single source file — the framework normalises the name at bind time.
Using the Properties Bean
Inject the class just like any other Spring bean:
Because the properties class is a real bean, you get constructor injection, testability, and IDE navigation for free.
Using Java Records (Spring Boot 3.x)
Spring Boot 3 supports binding directly to Java records. Records are immutable by design, which is ideal for configuration that should never change after startup:
Nested Properties
Configuration groups can be nested to any depth. Consider a service that talks to an external API with its own retry policy:
Validation with Bean Validation
Add @Validated to the class and use standard Bean Validation annotations on fields. Spring Boot runs validation at startup and fails fast with a clear error if a constraint is violated — rather than blowing up at runtime inside business logic.
spring-boot-starter-validation on the classpath. If you annotate fields with @NotBlank but forget the starter, the annotations are silently ignored at startup and you get no validation at all. Always verify the dependency is present.
IDE Metadata Auto-Complete
Add the annotation processor to your pom.xml so IDEs generate auto-complete and documentation for your custom prefixes:
At compile time the processor writes META-INF/spring-configuration-metadata.json. IntelliJ IDEA and VS Code read this file to offer property-name completion and inline documentation inside application.properties.
@ConfigurationProperties vs @Value — Decision Guide
- Use
@Valuefor a single, isolated property — for example a feature flag or a simple timeout that doesn't belong to a logical group. - Use
@ConfigurationPropertieswhenever two or more properties share a logical prefix, especially when the group is injected into multiple beans, needs default values, or must be validated at startup. - Never mix the two approaches for the same conceptual group — pick one and be consistent.
Summary
@ConfigurationProperties turns a flat key-value namespace into a structured, type-safe object. You gain IDE auto-complete, relaxed binding from any source (properties file, YAML, environment variable, command-line argument), startup validation, and a single place to document every setting a feature requires. In the next lesson you will see how Spring Profiles let you swap entire sets of these properties depending on the environment.