Spring Boot
@Value annotation
application properties
Java programming
Spring framework

Spring Boot Value Properties

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Spring Boot property injection with @Value is convenient for small configuration needs, but it can become hard to maintain when settings grow across modules. The main challenge is balancing convenience with type safety, validation, and clear property ownership. A strong approach uses @Value selectively and moves grouped settings to typed configuration classes.

Basic @Value Injection Pattern

For a small number of independent flags, @Value is concise.

java
1import org.springframework.beans.factory.annotation.Value;
2import org.springframework.stereotype.Component;
3
4@Component
5public class FeatureFlags {
6
7    @Value("${app.feature.audit-enabled:false}")
8    private boolean auditEnabled;
9
10    @Value("${app.feature.max-retries:3}")
11    private int maxRetries;
12
13    public boolean isAuditEnabled() {
14        return auditEnabled;
15    }
16
17    public int getMaxRetries() {
18        return maxRetries;
19    }
20}

Defaults are useful for local runs, but required production values should often fail fast if missing.

Understand Property Source Precedence

Unexpected values are usually precedence issues, not injection bugs.

Typical precedence includes:

  • command-line arguments
  • environment variables
  • profile-specific config files
  • base application config

Runtime override example:

bash
java -jar app.jar --app.feature.max-retries=10

Environment variable mapping example:

bash
export APP_FEATURE_MAX_RETRIES=7

Move Grouped Settings to @ConfigurationProperties

When settings share a prefix, typed binding scales better than many scattered @Value fields.

java
1import jakarta.validation.constraints.Min;
2import jakarta.validation.constraints.NotBlank;
3import org.springframework.boot.context.properties.ConfigurationProperties;
4import org.springframework.validation.annotation.Validated;
5
6@Validated
7@ConfigurationProperties(prefix = "app.mail")
8public class MailProperties {
9
10    @NotBlank
11    private String host;
12
13    @Min(1)
14    private int port = 25;
15
16    private boolean enabled = true;
17
18    public String getHost() {
19        return host;
20    }
21
22    public void setHost(String host) {
23        this.host = host;
24    }
25
26    public int getPort() {
27        return port;
28    }
29
30    public void setPort(int port) {
31        this.port = port;
32    }
33
34    public boolean isEnabled() {
35        return enabled;
36    }
37
38    public void setEnabled(boolean enabled) {
39        this.enabled = enabled;
40    }
41}

This improves readability, reuse, and startup validation.

Test Property Binding Explicitly

Configuration behavior should be tested like code.

java
1import org.junit.jupiter.api.Test;
2import org.springframework.beans.factory.annotation.Autowired;
3import org.springframework.boot.test.context.SpringBootTest;
4
5import static org.assertj.core.api.Assertions.assertThat;
6
7@SpringBootTest(properties = {
8    "app.mail.host=test.local",
9    "app.mail.port=2525",
10    "app.mail.enabled=true"
11})
12class MailPropertiesTest {
13
14    @Autowired
15    MailProperties mailProperties;
16
17    @Test
18    void bindsCorrectly() {
19        assertThat(mailProperties.getHost()).isEqualTo("test.local");
20        assertThat(mailProperties.getPort()).isEqualTo(2525);
21        assertThat(mailProperties.isEnabled()).isTrue();
22    }
23}

Binding tests prevent silent drift after refactors and upgrades.

Key Migration and Backward Compatibility

When renaming properties, avoid abrupt cutovers. Keep compatibility mapping for one release window, communicate deprecations, and remove old keys after adoption is confirmed. This minimizes rollout risk across multiple environments.

Documentation and Discoverability

Configuration quality improves when teams document each property key, default behavior, and allowed ranges in one place. This reduces tribal knowledge and helps operators diagnose misconfiguration without reading source code internals.

For larger systems, generate metadata and publish configuration references alongside release notes. Consistent naming conventions such as app.feature.* also improve discoverability and reduce duplicate keys across teams. This documentation should be reviewed during release cycles so deprecations and new keys remain synchronized with actual runtime behavior.

Practical Decision Guide

Use this simple rule:

  • one or two unrelated flags, use @Value
  • grouped domain settings, use @ConfigurationProperties
  • sensitive values, inject from external secret sources

This keeps configuration structure predictable as projects grow.

Common Pitfalls

  • Overusing @Value and scattering string keys across classes.
  • Adding defaults where missing values should fail startup.
  • Ignoring precedence and debugging the wrong config source.
  • Skipping validation for range-constrained numeric fields.
  • Treating configuration as untested infrastructure.

Summary

  • @Value is best for small, isolated property injection cases.
  • Property precedence explains many surprising runtime values.
  • Use typed @ConfigurationProperties for grouped settings.
  • Validate and test configuration binding to avoid deployment surprises.
  • Plan key migrations with compatibility windows, not abrupt renames.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.