Configuration & Actuator
application.yml structure, externalized config and profiles, and Actuator health checks and metrics in production.
application.yml structure
Spring Boot centralizes configuration in application.yml (or application.properties) at src/main/resources. YAML's nesting maps naturally onto the dotted property names Spring Boot uses internally:
server:
port: 8080
spring:
application:
name: bookstore-service
datasource:
url: jdbc:postgresql://localhost:5432/bookstore
username: app_user
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
show-sql: false
logging:
level:
root: INFO
com.example.bookstore: DEBUG
The equivalent .properties form is flatter but expresses the same structure:
server.port=8080
spring.application.name=bookstore-service
spring.datasource.url=jdbc:postgresql://localhost:5432/bookstore
spring.datasource.username=app_user
spring.datasource.password=${DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=validate
logging.level.root=INFO
${DB_PASSWORD} above pulls from an environment variable at startup — never commit real credentials into application.yml.
Externalized configuration and profiles
Spring Boot resolves the same property from multiple sources, in a defined precedence order (highest wins): command-line arguments, environment variables, then application-{profile}.yml, then the base application.yml. This lets the exact same packaged JAR run correctly across dev, staging, and production by changing only the environment it's deployed into — no rebuild required.
# application.yml — shared defaults
spring:
jpa:
show-sql: false
# application-dev.yml — active only when the "dev" profile is active
spring:
datasource:
url: jdbc:h2:mem:devdb
jpa:
show-sql: true
java -jar app.jar --spring.profiles.active=dev
Type-safe configuration classes are the recommended way to consume a related group of properties, instead of scattering @Value annotations:
app:
mail:
from-address: noreply@bookstore.example
retry-count: 3
@ConfigurationProperties(prefix = "app.mail")
public record MailProperties(String fromAddress, int retryCount) {
}
@Configuration
@EnableConfigurationProperties(MailProperties.class)
public class MailConfig {
}
Spring Boot Actuator
Actuator exposes production-facing operational endpoints — health, metrics, environment info — without you writing any of that plumbing yourself. Add it as a dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
By default, only /actuator/health is exposed over HTTP. Enable more endpoints deliberately in configuration:
management:
endpoints:
web:
exposure:
include: health, info, metrics
endpoint:
health:
show-details: when-authorized
curl localhost:8080/actuator/health
{ "status": "UP" }
With show-details enabled and a database configured, the same endpoint reports on each dependency Spring Boot knows how to check:
{
"status": "UP",
"components": {
"db": { "status": "UP", "details": { "database": "PostgreSQL" } },
"diskSpace": { "status": "UP" }
}
}
/actuator/metrics exposes counters and timers (request latency, JVM memory, thread pool usage) that feed directly into monitoring systems like Prometheus.
Why this matters in production: a load balancer or orchestrator (Kubernetes, ECS) needs a reliable way to know whether an instance is actually healthy before routing traffic to it, and whether to restart it if it isn't — that's exactly what a /health liveness/readiness check is for. Metrics endpoints feed dashboards and alerting, turning "is the service slow right now?" from a guess into a graph. Actuator is what makes a Spring Boot service observable without hand-building any of this from scratch.
Common mistakes
- Exposing every Actuator endpoint (
include: "*") on a public-facing port — endpoints like/actuator/envor/actuator/heapdumpcan leak secrets or internal details and should be restricted or placed behind authentication. - Committing real secrets directly into
application.ymlinstead of referencing environment variables or a secrets manager. - Never checking
/actuator/healthfrom the deployment platform's health-check configuration, leaving a struggling instance in rotation instead of being pulled out automatically. - Scattering many individual
@Valueproperties instead of grouping a related set into one@ConfigurationPropertiesclass.