DevNotes
Support
Spring Boot · Chapter 28

@ConfigurationProperties

Type-safe configuration binding — prefixes, relaxed binding, nested objects, lists, maps, Duration and DataSize, validation, constructor binding and records, registration options and the Binder internals.

◷ 7 min read§ 22 sections? 10 interview questions{ } 15 code examples

#Introduction

@ConfigurationProperties is the enterprise-standard way to bind external configuration into Java objects. Beginners often use @Value everywhere; experienced Spring Boot developers use @ConfigurationProperties for maintainable, type-safe and validated configuration.

Almost every enterprise application has configuration classes for the database, Redis, Kafka, RabbitMQ, JWT, AWS, Azure, SMTP, payment gateways, Elasticsearch and external APIs.

Interviewers frequently ask: What is @ConfigurationProperties? @Value vs @ConfigurationProperties? What is relaxed binding? What is constructor binding? How are nested objects, lists and maps bound? How does validation work? Which internal classes perform the binding?

#What is @ConfigurationProperties?

It binds a group of related configuration properties into a Java object.

Text
mail.host=smtp.gmail.com
mail.port=587
mail.username=admin
mail.password=secret

Instead of writing:

Java
@Value("${mail.host}")
private String host;

@Value("${mail.port}")
private int port;

@Value("${mail.username}")
private String username;

@Value("${mail.password}")
private String password;

use:

Java
@ConfigurationProperties(prefix = "mail")
public class MailProperties {
    private String host;
    private int port;
    private String username;
    private String password;
    // getters and setters
}

Cleaner. Safer. The enterprise standard.

#Why Was It Introduced?

Imagine:

Text
payment.timeout=30
payment.currency=USD
payment.retry=5
payment.api-key=abc123
payment.base-url=https://api.example.com
payment.max-connections=20
payment.read-timeout=5000
payment.connect-timeout=3000

With @Value, after 20–30 properties, maintenance becomes difficult. Instead: one PaymentProperties object holds all payment configuration.

#Basic Example

Text
app:
  server:
    host: localhost
    port: 8080
Java
@Component
@ConfigurationProperties(prefix = "app.server")
public class ServerProperties {
    private String host;
    private int port;
    // getters/setters
}
Java
@Service
public class ServerService {

    private final ServerProperties properties;

    public ServerService(ServerProperties properties) {
        this.properties = properties;
    }
}

Internal Architecture

application.yml
ConfigData loader
Environment
Binder
@ConfigurationProperties
Java object → Spring bean

#Property Prefix

Java
@ConfigurationProperties(prefix = "database")

Spring binds database.host, database.port, database.username and database.password. Only properties beginning with database are considered.

#Relaxed Binding

Interview favourite. Spring Boot understands multiple naming styles. For the Java field private int maxConnections; (with prefix payment), all of these bind:

Text
payment.max-connections=20      (kebab-case — recommended in files)
payment.maxConnections=20       (camelCase)
payment.max_connections=20      (underscore)
PAYMENT_MAXCONNECTIONS=20       (environment variable)

Everything maps to maxConnections.

Configuration
Normalize the name
Relaxed binder
Java field

#Nested Objects

Text
database:
  host: localhost
  pool:
    max-size: 30
    timeout: 5000
Java
@ConfigurationProperties(prefix = "database")
public class DatabaseProperties {

    private String host;
    private Pool pool;

    public static class Pool {
        private int maxSize;
        private int timeout;
        // getters/setters
    }
}
  • DatabaseProperties
    • host = localhost
    • Pool
      • maxSize = 30
      • timeout = 5000

#List Binding

Text
application:
  roles:
    - ADMIN
    - USER
    - MANAGER
Java
private List<String> roles;   // ADMIN, USER, MANAGER

No SpEL required.

#Map Binding

Text
application:
  headers:
    Authorization: JWT
    Version: v1
Java
private Map<String, String> headers;

Bound automatically.

#Duration, DataSize and Enums

Text
cache:
  timeout: 30s
Java
private Duration timeout;   // also: 5m, 2h, 1d
Text
upload:
  max-file-size: 100MB
Java
private DataSize maxFileSize;   // 100 MB
Java
public enum Mode {
    DEV,
    PROD
}

// application.mode: PROD → Mode.PROD

All converted automatically.

Type Conversion

Property valueJava type
"8080"int
"30s"Duration
"100MB"DataSize
"PROD"Enum

#Validation

Interview favourite.

Java
@ConfigurationProperties(prefix = "mail")
@Validated
public class MailProperties {

    @NotBlank
    private String host;

    @Min(1)
    private int port;
}

With mail.port=-1, application startup fails. Very useful — configuration errors are caught at startup, not in production traffic.

#Constructor Binding

Spring Boot 3.x automatically uses constructor binding when a properties class has a single parameterized constructor, so an explicit @ConstructorBinding is unnecessary in most cases (it's only needed to pick one of several constructors).

Java
@ConfigurationProperties(prefix = "payment")
public class PaymentProperties {

    private final String currency;
    private final int timeout;

    public PaymentProperties(String currency, int timeout) {
        this.currency = currency;
        this.timeout = timeout;
    }

    public String getCurrency() {
        return currency;
    }

    public int getTimeout() {
        return timeout;
    }
}

Benefits: immutable, thread-safe, easier testing. A Java record works the same way and is even shorter:

Java
@ConfigurationProperties(prefix = "payment")
public record PaymentProperties(String currency, int timeout) {
}

#Registration

There are three common ways to turn the class into a bean:

Java
// 1. As a component
@Component
@ConfigurationProperties(prefix = "mail")

// 2. Explicitly
@EnableConfigurationProperties(MailProperties.class)

// 3. By scanning — Spring scans all configuration-property classes
@ConfigurationPropertiesScan

(Constructor-bound classes and records can't use @Component; register them with option 2 or 3.)

#Internal Binding Flow

SpringApplication.run()
ConfigData → Environment created
Binder
ConfigurationPropertySource
BindHandler
ConversionService
Validation
Java object
Bean registered

Important Internal Classes

ClassResponsibility
BinderCore binding engine
ConfigurationPropertySourceReads configuration values
ConfigurationPropertyNameNormalizes property names
BindHandlerControls the binding process
BindContextMaintains binding state
ApplicationConversionServiceConverts values to target types
ConfigurationPropertiesBindingPostProcessorProcesses @ConfigurationProperties beans

#Metadata Generation

XML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

This generates metadata that gives your IDE auto-completion, documentation and property validation for your custom configuration properties.

#@Value vs @ConfigurationProperties

@Value@ConfigurationProperties
Single valuesEntire object
Supports SpELConfiguration binding only
Good for 1–3 propertiesGood for many related properties
Less maintainableHighly maintainable
Hard to validateEasy validation
Repeated annotationsCentralized configuration

Enterprise recommendation: few properties → @Value; many properties → @ConfigurationProperties.

#Enterprise Example

  • PaymentProperties
    • API URL
    • Timeout
    • Retry count
    • Credentials
    • SSL
    • Connection pool
One configuration bean instead of 25 individual @Value annotations

#Common Mistakes

  • Forgetting registration — a class with only @ConfigurationProperties (no @Component, @EnableConfigurationProperties or @ConfigurationPropertiesScan) never becomes a bean.
  • Using @Value everywhere — large applications become hard to maintain.
  • Mutable configuration without need — prefer immutable classes (constructor binding, records).
  • No validation — invalid configuration reaches production. Validate critical settings.
  • Wrong prefix — @ConfigurationProperties(prefix = "database") with db.host=localhost binds nothing, because the prefixes don't match.

#Best Practices

  • Group related properties into dedicated classes.
  • Use constructor binding and immutable fields.
  • Validate important configuration with Bean Validation.
  • Use meaningful prefixes (mail, payment, security, redis).
  • Keep secrets out of source control — use environment variables or secret managers.

#Real Enterprise Structure

  • config
    • JwtProperties
    • MailProperties
    • KafkaProperties
    • RedisProperties
    • AwsProperties
    • PaymentProperties
    • SecurityProperties
    • StorageProperties
Each configuration area has its own strongly typed class

#Interview Questions

Q1What is @ConfigurationProperties?

It binds a group of related configuration properties into a strongly typed Java object.

Q2Why is it better than @Value?

Better maintainability, validation, type-safe binding, nested structures and cleaner code for grouped configuration.

Q3What is relaxed binding?

Spring Boot accepts different naming conventions (kebab-case, camelCase, snake_case, uppercase environment variables) and maps them to the same Java field.

Q4Can it bind lists?

Yes — a YAML list such as roles: [ADMIN, USER] binds to List<String> roles.

Q5Can it bind maps?

Yes.

Q6Can it bind nested objects?

Yes — nested YAML structures map naturally to nested Java classes.

Q7Which class performs binding?

The core engine is Binder, assisted by ConfigurationPropertiesBindingPostProcessor during bean initialization.

Q8Can validation be applied?

Yes — @Validated together with Bean Validation annotations such as @NotBlank, @Min or @Max.

Q9Is @ConstructorBinding still required in Spring Boot 3?

In most cases no — a class with a single parameterized constructor is automatically constructor-bound.

Q10Which annotation enables scanning of configuration property classes?

@ConfigurationPropertiesScan.

#Key Takeaways

  • @ConfigurationProperties is the preferred way to manage structured configuration.
  • It binds related properties into a single, strongly typed object.
  • Relaxed binding maps multiple naming conventions to the same field.
  • Nested objects, collections, maps, Duration, DataSize and enums bind automatically.
  • Constructor binding with immutable classes (or records) is recommended in Boot 3.
  • Validation catches configuration errors at startup.
  • Binder and ConfigurationPropertiesBindingPostProcessor power the binding.