Configuration
application.properties, application.yml, @Value, @ConfigurationProperties, config precedence
Configuration
1. Definition
Spring Boot configuration is the system for managing external settings (properties, profiles, secrets). Spring Boot follows the externalized configuration principle: application behavior is controlled from sources outside the code (property files, environment variables, command-line arguments).
The two main configuration formats:
- application.properties â simple key-value pairs
- application.yml â YAML hierarchy (indentation-based)
# application.properties
server.port=8081
spring.datasource.url=jdbc:postgresql://localhost/mydb
# application.yml
server:
port: 8081
spring:
datasource:
url: jdbc:postgresql://localhost/mydb
2. Core Concepts
Property source hierarchy
Spring Boot reads configuration from 17+ sources. Higher priority overrides lower:
- Command-line arguments (
--server.port=9090) - SPRING_APPLICATION_JSON (inline JSON)
- Servlet/JNDI parameters
- OS environment variables (
SERVER_PORT=9090) - Profile-specific property files (
application-prod.properties) - Application property files (
application.properties) - @PropertySource annotation
- Default properties (SpringApplication.setDefaultProperties)
@Value annotation
Injecting individual properties:
@Component
public class MyComponent {
@Value("${server.port}")
private int port;
@Value("${app.name:DefaultApp}")
private String appName; // default value after colon
@Value("${app.features.enabled:false}")
private boolean featuresEnabled;
}
@ConfigurationProperties
Type-safe property binding to a POJO:
@ConfigurationProperties(prefix = "app.datasource")
public class DataSourceProperties {
private String url;
private String username;
private String password;
private int maxPoolSize = 10;
// getters and setters
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public int getMaxPoolSize() { return maxPoolSize; }
public void setMaxPoolSize(int maxPoolSize) { this.maxPoolSize = maxPoolSize; }
}
Profiles
Environment-specific configuration:
# application-dev.properties
server.port=8080
spring.datasource.url=jdbc:h2:mem:devdb
# application-prod.properties
server.port=443
spring.datasource.url=jdbc:postgresql://prod-host/mydb
Activation: spring.profiles.active=dev or --spring.profiles.active=prod.
3. Practical Usage
Property file locations
src/main/resources/
âââ application.properties â default
âââ application.yml â alternative (YAML)
âââ application-dev.properties â dev profile
âââ application-prod.properties â prod profile
âââ application-test.properties â test profile
YAML advantages and disadvantages
# Hierarchical structure â more readable
spring:
datasource:
url: jdbc:postgresql://localhost/mydb
username: admin
password: secret
jpa:
hibernate:
ddl-auto: update
show-sql: true
- â Hierarchical, less repetition
- â Native list support
- â Indentation-sensitive (tab vs space errors)
- â @PropertySource does not support YAML
@ConfigurationProperties activation
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class AppConfig {
}
// OR: @ConfigurationPropertiesScan on the application class
@SpringBootApplication
@ConfigurationPropertiesScan
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Property validation
@ConfigurationProperties(prefix = "app.mail")
@Validated
public class MailProperties {
@NotBlank
private String host;
@Min(1) @Max(65535)
private int port = 587;
@Email
private String from;
// getters and setters
public String getHost() { return host; }
public void setHost(String host) { this.host = host; }
public int getPort() { return port; }
public void setPort(int port) { this.port = port; }
public String getFrom() { return from; }
public void setFrom(String from) { this.from = from; }
}
4. Code Examples
@Value vs @ConfigurationProperties
// @Value â individual properties, simple cases
@Component
public class SimpleConfig {
@Value("${app.name}")
private String appName;
@Value("${app.timeout:5000}")
private long timeout;
}
// @ConfigurationProperties â group binding, type-safe
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private long timeout = 5000;
private final Security security = new Security();
public static class Security {
private String secret;
private long tokenExpiry = 3600;
// getters + setters
public String getSecret() { return secret; }
public void setSecret(String s) { this.secret = s; }
public long getTokenExpiry() { return tokenExpiry; }
public void setTokenExpiry(long t) { this.tokenExpiry = t; }
}
// getters + setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public long getTimeout() { return timeout; }
public void setTimeout(long timeout) { this.timeout = timeout; }
public Security getSecurity() { return security; }
}
Relaxed binding
Spring Boot uses relaxed binding:
# All of these refer to the same property:
app.datasource.max-pool-size=10 # kebab-case (recommended)
app.datasource.maxPoolSize=10 # camelCase
app.datasource.max_pool_size=10 # underscore
APP_DATASOURCE_MAX_POOL_SIZE=10 # UPPER_CASE (env var)
Profile-specific beans
@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:postgresql://prod-host/mydb");
return ds;
}
}
Environment variable â property mapping
# Shell / Docker
export SPRING_DATASOURCE_URL=jdbc:postgresql://prod/mydb
export SERVER_PORT=9090
export APP_SECURITY_SECRET=my-secret-key
Mapping rule: UPPER_CASE + underscore â lower.case + dot.
5. Trade-offs
| Aspect | @Value | @ConfigurationProperties |
|---|---|---|
| Simplicity | â Quick, single property | â More boilerplate |
| Type safety | â String-based, runtime errors | â Compile-time types |
| Validation | â No built-in | â @Validated + JSR-303 |
| IDE support | â Limited | â Autocomplete (metadata) |
| Grouping | â Scattered | â Hierarchical POJO |
| SpEL | â Supported | â Not supported |
Properties vs YAML
| Aspect | .properties | .yml |
|---|---|---|
| Format | Key=value | Hierarchical |
| Repetition | Full prefix on every line | No repetition |
| Lists | list[0]=a, list[1]=b |
- a + - b |
| @PropertySource | â Supported | â Not supported |
| Error risk | Low | Indentation sensitive |
6. Common Mistakes
â @Value SpEL error
// WRONG: # instead of $ â SpEL, not property
@Value("#{server.port}") // â SpEL
private int port;
// CORRECT:
@Value("${server.port}") // â property placeholder
private int port;
â Missing property, no default
// WRONG: if property doesn't exist â startup error
@Value("${app.missing.property}")
private String value;
// CORRECT: default value
@Value("${app.missing.property:fallback}")
private String value;
â YAML indentation error
# WRONG: tab character in YAML
spring:
datasource: # â TAB was here! Error!
url: jdbc:...
# CORRECT: spaces
spring:
datasource:
url: jdbc:...
â Missing @ConfigurationProperties registration
// WRONG: properties class not registered â properties are null
@ConfigurationProperties(prefix = "app")
public class AppProps { ... }
// CORRECT: @EnableConfigurationProperties OR @ConfigurationPropertiesScan
@Configuration
@EnableConfigurationProperties(AppProps.class)
public class Config { }
â Misunderstanding property override order
Command-line arguments (--server.port=9090) always override application.properties values. Developers sometimes don't understand why the file-based value doesn't take effect.
7. Deep Dive
Config file search order
Spring Boot searches for config files in these locations:
file:./config/(project root /config folder)file:./config/*/(subdirectories)file:./(project root)classpath:/config/(classpath /config)classpath:/(classpath root)
spring.config.import (Boot 2.4+)
# Import external files
spring.config.import=optional:file:/etc/myapp/config.properties
spring.config.import=optional:configserver:http://config-server:8888
@ConfigurationProperties metadata
Generate metadata for IDE autocomplete:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
This generates a META-INF/spring-configuration-metadata.json file.
Immutable @ConfigurationProperties (record)
@ConfigurationProperties(prefix = "app.mail")
public record MailProperties(
@NotBlank String host,
@DefaultValue("587") int port,
@Email String from
) {}
Constructor binding: no setters needed, the record is immutable.
Secret management
# NEVER commit secrets!
# Use environment variables:
spring.datasource.password=${DB_PASSWORD}
# Or Spring Cloud Config + Vault
spring.config.import=vault://secret/myapp
8. Interview Questions
What is the difference between application.properties and application.yml? Properties: key=value, YAML: hierarchical indentation. Properties supports @PropertySource, YAML doesn't. YAML is more readable but indentation-sensitive.
What is the property source priority order? Command line > env vars > profile-specific file > application.properties > defaults. Higher priority overrides lower.
When should you use @Value vs @ConfigurationProperties? @Value: individual properties, SpEL needed. @ConfigurationProperties: group binding, validation, IDE autocomplete, hierarchical configuration.
What is relaxed binding? Spring Boot automatically understands different formats:
max-pool-size=maxPoolSize=MAX_POOL_SIZE.How do you validate configuration properties? @Validated + JSR-303 annotations (@NotBlank, @Min, @Max, @Email) on the @ConfigurationProperties class.
What is spring.config.import? Boot 2.4+ feature: imports external files, config server, vault into the property source.
How do you handle secrets? Environment variables, Spring Cloud Config + Vault, Kubernetes secrets â never commit to property files.
9. Glossary
| Term | Meaning |
|---|---|
| Property source | Source of configuration values (file, env var, command line) |
| @Value | Individual property injection with SpEL support |
| @ConfigurationProperties | Type-safe, grouped property binding |
| Relaxed binding | Automatic format recognition (kebab, camel, upper) |
| Profile | Environment-specific configuration (dev, prod, test) |
| BOM | Bill of Materials â version management |
| spring.config.import | External configuration import (Boot 2.4+) |
| Configuration processor | Annotation processor for IDE metadata generation |
| Constructor binding | Immutable @ConfigurationProperties (record, final fields) |
| Externalized configuration | Controlling app behavior from outside the code |
10. Cheatsheet
# Property source priority (decreasing):
# 1. --command-line
# 2. SPRING_APPLICATION_JSON
# 3. OS env var (SERVER_PORT=9090)
# 4. application-{profile}.properties
# 5. application.properties
# 6. @PropertySource
# 7. SpringApplication.setDefaultProperties
# Profile activation
spring.profiles.active=dev,metrics
# Config import (Boot 2.4+)
spring.config.import=optional:file:/etc/myapp/config.properties
# Relaxed binding
app.max-pool-size=10 # kebab (recommended in .properties)
APP_MAX_POOL_SIZE=10 # UPPER (env var)
// @Value â individual, SpEL
@Value("${app.name:default}")
private String name;
// @ConfigurationProperties â grouped, type-safe
@ConfigurationProperties(prefix = "app")
@Validated
public class AppProps {
@NotBlank private String name;
@Min(1) private int port;
}
// Record binding (immutable)
@ConfigurationProperties(prefix = "app")
public record AppProps(@NotBlank String name, @DefaultValue("8080") int port) {}
đź Games
10 questions