Why You Should Ditch @Value in Favor of @ConfigurationProperties
Introduction
When working with Spring Boot, it’s common to externalize configuration into application.yml or application.properties. The most common way to inject these values (at least for me) has been using the @Value annotation.
Recently, I came across some drawbacks of @Value, and this post explores why @ConfigurationProperties is a better alternative — more type-safe, maintainable, and scalable.
The Problems with @Value
1. Scattered Configuration
@Value is often applied directly on class fields, leading to scattered configuration usage throughout your codebase. This makes it hard to track where certain values are used.
@Value("${app.name}")
private String appName;
@Value("${app.timeout}")
private int timeout;
2. Lack of Type-Safety
With @Value, Spring tries to convert values into types like int or boolean, but there’s no structure-level validation.
3. No Support for Nested Configurations
Hierarchical configuration becomes messy with @Value.
app.email.host=smtp.example.com
app.email.port=587
app.email.username=user
app.email.password=secret
You’d need to inject each field manually:
@Value("${app.email.host}")
private String host;
@Value("${app.email.port}")
private int port;
@Value("${app.email.username}")
private String username;
@Value("${app.email.password}")
private String password;
Notice the app.email prefix repeated everywhere… 🥲
The Solution: @ConfigurationProperties 🎉
This lets you bind entire property groups into a class. It’s cleaner, more readable, and supports nested structures.
How to Use @ConfigurationProperties
1. Define a Configuration Class
@Component
@ConfigurationProperties(prefix = "app.email")
public class EmailConfig {
private String host;
private int port;
private String username;
private String password;
// Getters and setters
}
2. Add Properties to application.yml
app:
email:
host: smtp.example.com
port: 587
username: user
password: secret
3. Inject the Config Class
@RestController
public class EmailController {
private final EmailConfig emailConfig;
public EmailController(EmailConfig emailConfig) {
this.emailConfig = emailConfig;
}
@GetMapping("/email-config")
public String getEmailConfig() {
return "Host: " + emailConfig.getHost() + ", Port: " + emailConfig.getPort();
}
}
Why @ConfigurationProperties Wins
✅ Type-Safe Configuration
Fields are bound directly and checked at startup — no more silent runtime errors due to invalid values.
✅ Cleaner, Grouped Code
Your config is all in one class instead of scattered across your service layers.
✅ Supports Nested & Complex Structures
Example with lists:
app:
servers:
- url: https://server1.example.com
port: 8080
- url: https://server2.example.com
port: 9090
@Component
@ConfigurationProperties(prefix = "app")
public class AppConfig {
private List<Server> servers;
public static class Server {
private String url;
private int port;
// Getters and setters
}
}
✅ Validation Support
@Component
@ConfigurationProperties(prefix = "app.email")
public class EmailConfig {
@NotNull
private String host;
@Min(1)
@Max(65535)
private int port;
// Getters and setters
}
Conclusion
Switching from @Value to @ConfigurationProperties helps you write more robust and scalable Spring Boot code.
If you find yourself sprinkling @Value annotations everywhere, try moving to @ConfigurationProperties. You’ll thank yourself later.