Spring Boot - Externalized Configuration
What it is: Spring Boot lets you keep settings (DB URLs, ports, feature flags, etc.) outside your code/jar so you can change behavior without rebuilding.
Why itβs useful
- Different config per environment (dev/stage/prod) via profiles.
- Override at deploy time using env vars or CLI without touching files.
- Type-safe binding of config into POJOs with validation.
Configuration sources & precedence
(Higher items override lower ones if the same key is defined.)
-
Command line args
java -jar app.jar --server.port=9090 --app.feature.enabled=true
-
Java system properties:
-Dserver.port=9090
-
OS environment variables (map
.
to_
, uppercase):SPRING_DATASOURCE_URL=jdbc:...
- SPRING_APPLICATION_JSON (inline JSON env var)
-
Config files (properties or YAML), searched in:
./config/
,./
,classpath:/config/
,classpath:/
Common filenames:application.yml
,application.properties
, plus profile variants. -
Defaults (programmatic):
SpringApplication.setDefaultProperties(...)
You can also point to custom paths:
--spring.config.location=file:/etc/myapp/,classpath:/extra/
Profiles (per-environment config)
Activate
- CLI:
--spring.profiles.active=dev
- Env var:
SPRING_PROFILES_ACTIVE=prod
Files
-
application.yml
(common) -
application-dev.yml
,application-prod.yml
(overrides)
Multi-document YAML example
# application.yml
app:
title: "MyApp"
---
spring.config.activate.on-profile: dev
server.port: 8081
app.title: "MyApp (DEV)"
---
spring.config.activate.on-profile: prod
server.port: 8080
Reading config in code
A) Type-safe binding with @ConfigurationProperties
(recommended)
Supports lists, maps, durations, data sizes, and validation with relaxed binding.
YAML
app:
storage:
location: /var/data
max-size: 256MB
tags: [fast, ssd]
Java class
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import jakarta.validation.constraints.NotBlank;
import java.util.List;
import org.springframework.util.unit.DataSize;
@Validated
@ConfigurationProperties(prefix = "app.storage")
public class StorageProps {
@NotBlank private String location;
private DataSize maxSize; // parses "256MB" automatically
private List<String> tags;
// getters/setters
}
Enable scanning (Boot 2.2+)
@SpringBootApplication
@ConfigurationPropertiesScan // picks up @ConfigurationProperties classes
public class App { }
Inject/use it
@Service
public class StorageService {
private final StorageProps props;
public StorageService(StorageProps props) { this.props = props; }
}
B) Quick injections with @Value
@Value("${app.feature.enabled:false}")
private boolean enabled;
Good for one-offs; prefer @ConfigurationProperties
for grouped settings.
Environment variable mapping (relaxed binding)
- Property:
spring.datasource.url
- Env var:
SPRING_DATASOURCE_URL
Dots β underscores, kebab/camel accepted, case-insensitive.
Config Data API (Boot 2.4+)
Import extra files/dirs/secrets declaratively:
spring:
config:
import:
- optional:file:/etc/myapp/ # folder
- optional:configtree:/run/secrets/ # k8s secrets as key-per-file
Tip: Prefix with optional:
so startup wonβt fail if a location is missing.
Secrets & external stores
- Prefer env vars, mounted secrets (
configtree
), or Spring Cloud Config/Vault/AWS Secrets Manager. - Spring Boot doesnβt encrypt values by itself; use Vault or solutions like Jasypt if required.
Handy patterns
Placeholders & defaults
app:
api-url: "${API_URL:https://api.example.com}" # env var override or default
Profile-specific beans
@Profile("prod")
@Bean DataSource prodDs(...) { ... }
Validation on configuration
@Validated
@ConfigurationProperties("app.mail")
class MailProps {
@jakarta.validation.constraints.NotBlank String host;
@jakarta.validation.constraints.Min(1) int poolSize = 5;
}
Quick checklist
- Shared config in
application.yml
; overrides inapplication-<profile>.yml
. - Activate with
SPRING_PROFILES_ACTIVE
. - Use
@ConfigurationProperties
+@ConfigurationPropertiesScan
for structured, validated settings. - Override at deploy time with env vars or CLI args (highest precedence).
- Avoid hardcoding secrets; inject securely via env/secrets managers.