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.