Spring Framework
ConfigurationProperties
Java Records
Spring Boot
Java Annotations

How to use ConfigurationProperties with Records?

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

@ConfigurationProperties works well with Java records because records give you immutable, concise configuration holders with almost no boilerplate. The main idea is to bind external configuration into a record whose components represent the properties under a common prefix. In modern Spring Boot, this is a clean alternative to mutable setter-based configuration beans.

A Basic Record Configuration Class

Suppose you have properties like these:

yaml
1app:
2  api:
3    base-url: https://example.com
4    timeout-seconds: 10

You can bind them into a record:

java
1import org.springframework.boot.context.properties.ConfigurationProperties;
2
3@ConfigurationProperties(prefix = "app.api")
4public record ApiProperties(
5    String baseUrl,
6    int timeoutSeconds
7) {
8}

The record components map naturally to configuration keys. Kebab-case properties bind to camelCase record components.

Enable Configuration Properties Scanning

Spring needs to discover the class. The common approach is enabling configuration properties scanning on your application.

java
1import org.springframework.boot.SpringApplication;
2import org.springframework.boot.autoconfigure.SpringBootApplication;
3import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
4
5@SpringBootApplication
6@ConfigurationPropertiesScan
7public class DemoApplication {
8    public static void main(String[] args) {
9        SpringApplication.run(DemoApplication.class, args);
10    }
11}

With scanning enabled, Spring can create the record-based bean automatically.

Inject the Record Like Any Other Bean

Once registered, the record can be injected into services or configuration classes.

java
1import org.springframework.stereotype.Service;
2
3@Service
4public class ApiClientService {
5    private final ApiProperties properties;
6
7    public ApiClientService(ApiProperties properties) {
8        this.properties = properties;
9    }
10
11    public void printConfig() {
12        System.out.println(properties.baseUrl());
13        System.out.println(properties.timeoutSeconds());
14    }
15}

Notice that record accessors are named after the components themselves, not getBaseUrl().

Nested Records Work Well Too

Complex configuration structures can be modeled with nested records.

java
1import org.springframework.boot.context.properties.ConfigurationProperties;
2
3@ConfigurationProperties(prefix = "app")
4public record AppProperties(
5    Security security,
6    Api api
7) {
8    public record Security(
9        boolean enabled,
10        String role
11    ) {}
12
13    public record Api(
14        String baseUrl,
15        int timeoutSeconds
16    ) {}
17}

Matching YAML:

yaml
1app:
2  security:
3    enabled: true
4    role: ADMIN
5  api:
6    base-url: https://example.com
7    timeout-seconds: 10

This keeps hierarchical configuration strongly typed and immutable.

Validation Still Applies

You can validate record-based configuration just as you would a regular properties class.

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.api")
8public record ApiProperties(
9    @NotBlank String baseUrl,
10    @Min(1) int timeoutSeconds
11) {
12}

If a property is missing or invalid, application startup fails early, which is usually exactly what you want for required configuration.

Version Considerations

Record support depends on using a Spring Boot version new enough to handle constructor-style binding cleanly. In modern Spring Boot, records work naturally because binding happens through the canonical constructor. In older Boot versions, you may see examples with @ConstructorBinding.

The practical rule is simple:

  • modern Spring Boot: records work cleanly with constructor binding semantics
  • older projects: verify whether explicit constructor binding annotations are still required

That version detail matters when migrating legacy code.

When Records Are a Good Fit

Records are especially good when configuration should be:

  • immutable after startup
  • simple and declarative
  • grouped by prefix
  • validated at startup

They are less attractive when you need unusual custom binding behavior or a lot of imperative configuration logic inside the properties class.

Common Pitfalls

The biggest mistake is forgetting to register the properties class through scanning or explicit enablement. The record then looks correct but never becomes a bean.

Another issue is using property names that do not map cleanly to the record components and then assuming binding is broken. Check the prefix and exact property names carefully.

Developers also sometimes write getter-style access like getBaseUrl(). Record components use accessor methods named exactly after the component.

Summary

  • '@ConfigurationProperties and Java records are a good match for immutable config.'
  • Use a record with a clear prefix and enable configuration properties scanning.
  • Inject the record like any other Spring bean.
  • Nested records work well for hierarchical settings.
  • Add validation so invalid configuration fails fast at startup.

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.