Spring Boot
application.yml
application.yml is an alternative to application.properties that uses YAML syntax — a hierarchical, human-readable format that eliminates the repetitive key prefixes of the flat properties format. For deeply nested configuration like Spring Boot's datasource, JPA, and security settings, YAML is significantly more readable. Both formats are fully supported and functionally equivalent.
YAML vs Properties
Both application.properties and application.yml configure the same Spring Boot auto-configuration. They are parsed into the same internal property model — there is no functional difference. The choice is purely about readability and team preference.
YAML's advantages: hierarchical structure eliminates repeated prefixes, lists and maps have natural syntax, multi-line strings are clean, and complex nested configuration is more readable.
Properties' advantages: simpler syntax with no indentation rules, universally familiar, easier to append single lines, and no risk of YAML parsing errors from incorrect indentation.
The key YAML rule: indentation must be consistent spaces (never tabs). Two spaces per level is the Spring Boot convention. A single YAML mistake — one wrong indentation — silently changes property keys and causes hard-to-diagnose misconfiguration.
YAML Syntax Fundamentals
Understanding YAML syntax rules prevents the indentation errors and type coercion surprises that are the most common YAML pitfalls.
yaml
# ── Key-value pairs ──────────────────────────────────────────────────
server:
port: 8080 # integer — no quotes needed
servlet:
context-path: /api # string — no quotes needed
# ── Strings ───────────────────────────────────────────────────────────
app:
name: MyApplication # unquoted — fine for simple strings
description: "My Spring Boot App" # quoted — use when string has special chars
message: 'It''s working' # single quotes — escape '' for literal '
multiline: | # literal block — preserves newlines
Line one
Line two
Line three
folded: > # folded block — newlines become spaces
This is a very long
description that wraps
# ── Numbers ───────────────────────────────────────────────────────────
server:
port: 8080 # int
tomcat:
connection-timeout: 5000 # int (milliseconds)
app:
jwt:
expiration: 86400 # int
rate: 0.15 # float
# ── Booleans ──────────────────────────────────────────────────────────
spring:
jpa:
show-sql: false # boolean — false/true (NOT yes/no in Spring YAML)
h2:
console:
enabled: true
# ── Lists ─────────────────────────────────────────────────────────────
spring:
profiles:
active:
- dev
- metrics
# Or inline list syntax:
spring:
profiles:
active: [dev, metrics]
# ── Maps ──────────────────────────────────────────────────────────────
logging:
level:
root: INFO
com.example: DEBUG
org.springframework.web: DEBUG
# ── Environment variable references ───────────────────────────────────
spring:
datasource:
password: ${DB_PASSWORD}
url: ${DATABASE_URL:jdbc:mysql://localhost:3306/mydb} # with defaultComplete application.yml
A complete, production-ready application.yml showing the full Spring Boot configuration for a REST API with JPA, Security, and Actuator — and how much cleaner YAML is compared to equivalent .properties.
yaml
# application.yml — complete Spring Boot configuration
server:
port: 8080
servlet:
context-path: /api
tomcat:
max-threads: 200
min-spare-threads: 10
connection-timeout: 5000
compression:
enabled: true
mime-types: application/json,text/html
min-response-size: 2048
shutdown: graceful
spring:
application:
name: myapp
datasource:
url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
username: root
password: ${DB_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
pool-name: myapp-pool
maximum-pool-size: 10
minimum-idle: 5
idle-timeout: 300000
connection-timeout: 20000
max-lifetime: 1200000
keepalive-time: 60000
jpa:
hibernate:
ddl-auto: validate
show-sql: false
open-in-view: false
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
default_batch_fetch_size: 16
jdbc:
batch_size: 25
flyway:
enabled: true
locations: classpath:db/migration
validate-on-migrate: true
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth.example.com
data:
redis:
host: ${REDIS_HOST:localhost}
port: 6379
timeout: 2000
cache:
type: redis
jackson:
serialization:
write-dates-as-timestamps: false
deserialization:
fail-on-unknown-properties: false
default-property-inclusion: non_null
servlet:
multipart:
max-file-size: 10MB
max-request-size: 50MB
lifecycle:
timeout-per-shutdown-phase: 30s
management:
endpoints:
web:
exposure:
include: health,info,metrics,loggers
endpoint:
health:
show-details: when-authorized
show-components: always
info:
env:
enabled: true
java:
enabled: true
logging:
level:
root: INFO
com.example: DEBUG
org.springframework.web: DEBUG
pattern:
console: "%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n"
file:
name: logs/myapp.log
max-size: 50MB
max-history: 30
app:
jwt:
secret: ${JWT_SECRET}
expiration: 86400
issuer: https://myapp.com
mail:
from: noreply@myapp.com
features:
payments:
enabled: true
notifications:
enabled: true
info:
app:
name: My Application
version: 2.1.0Profile-Specific YAML — spring.config.activate.on-profile
Spring Boot supports two approaches for profile-specific YAML: separate files (application-dev.yml) or multi-document YAML with --- separators in a single file. Both work identically.
yaml
# ── APPROACH 1: Separate files (same as .properties) ─────────────────
# application.yml — base config for all profiles
# application-dev.yml — dev overrides
# application-prod.yml — prod settings
# application-dev.yml:
spring:
datasource:
url: jdbc:h2:mem:devdb;MODE=MySQL
username: sa
password: ""
h2:
console:
enabled: true
jpa:
show-sql: true
hibernate:
ddl-auto: create-drop
logging:
level:
com.example: DEBUG
org.springframework.web: DEBUG
# ── APPROACH 2: Multi-document YAML (single file) ─────────────────────
# Use --- to separate YAML documents within one file
# Each document can target a specific profile
# application.yml with multiple documents:
---
# Document 1 — base config (no profile restriction):
server:
port: 8080
spring:
jpa:
show-sql: false
logging:
level:
root: INFO
---
# Document 2 — development overrides:
spring:
config:
activate:
on-profile: dev # only applied when 'dev' profile is active
datasource:
url: jdbc:h2:mem:devdb
username: sa
password: ""
jpa:
show-sql: true
hibernate:
ddl-auto: create-drop
logging:
level:
com.example: DEBUG
---
# Document 3 — production settings:
spring:
config:
activate:
on-profile: prod
datasource:
url: ${DATABASE_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 20
logging:
level:
root: WARN
com.example: INFOYAML Lists and Maps in Configuration
YAML's native list and map syntax makes complex configuration clean. Understanding how Spring Boot binds YAML lists and maps to Java types is essential for custom @ConfigurationProperties classes.
yaml
# YAML lists — bound to Java List<String>:
app:
allowed-origins:
- https://myapp.com
- https://admin.myapp.com
- http://localhost:3000
# Or inline list syntax:
app:
allowed-origins: [https://myapp.com, https://admin.myapp.com]
# Bound to a @ConfigurationProperties class:
# @ConfigurationProperties(prefix = "app")
# public class AppProperties {
# private List<String> allowedOrigins;
# }
# YAML maps — bound to Java Map<String, String>:
app:
external-services:
inventory: https://inventory:8082
pricing: https://pricing:8083
shipping: https://shipping:8084
# Or as typed sub-objects:
app:
services:
inventory:
url: https://inventory:8082
timeout: 5000
retry-count: 3
pricing:
url: https://pricing:8083
timeout: 3000
retry-count: 2
# List of objects — bound to List<ServiceConfig>:
app:
notification-channels:
- type: email
enabled: true
priority: 1
- type: sms
enabled: true
priority: 2
- type: push
enabled: false
priority: 3
# @ConfigurationProperties binding:
# public class AppProperties {
# private List<NotificationChannel> notificationChannels;
# }
# public record NotificationChannel(String type, boolean enabled, int priority) {}
# Logging levels as a map:
logging:
level:
root: INFO
com.example: DEBUG
com.example.security: WARN
org.springframework.web: DEBUG
org.hibernate.SQL: DEBUGYAML Pitfalls and How to Avoid Them
YAML's strict indentation rules and implicit type coercion cause subtle bugs that are hard to diagnose. These are the most common YAML mistakes in Spring Boot configuration.
yaml
# ── PITFALL 1: Tabs instead of spaces ────────────────────────────────
# WRONG — tabs cause org.yaml.snakeyaml.scanner.ScannerException:
server:
port: 8080 # tab indentation — INVALID YAML
# CORRECT — spaces only (2 spaces per level is Spring Boot convention):
server:
port: 8080
# ── PITFALL 2: Wrong indentation level ───────────────────────────────
# WRONG — incorrect indentation changes the property key:
spring:
datasource: # NOT under spring — becomes "datasource.url"
url: jdbc:mysql://...
# CORRECT:
spring:
datasource: # under spring — becomes "spring.datasource.url"
url: jdbc:mysql://...
# ── PITFALL 3: Unquoted special characters ────────────────────────────
# WRONG — colon in value without quotes:
app:
description: My App: Version 2 # colon causes YAML parse error
# CORRECT — quote strings containing special characters:
app:
description: "My App: Version 2"
url: "http://localhost:8080" # colons in URLs need quoting
# ── PITFALL 4: Yes/No interpreted as boolean ──────────────────────────
# WRONG — 'yes' and 'no' are booleans in YAML 1.1 (SnakeYAML):
feature:
enabled: yes # parsed as true — may not be what you want
# CORRECT — use true/false explicitly:
feature:
enabled: true
# ── PITFALL 5: Duplicate keys — last one wins silently ───────────────
spring:
datasource:
url: jdbc:h2:mem:devdb # first value
datasource: # duplicate key — no error, second wins
url: jdbc:mysql://... # this value is used
# ── PITFALL 6: Multi-document separator placement ─────────────────────
# WRONG — --- must be on its own line with no trailing spaces:
spring:
port: 8080
---spring: # wrong — must be on separate line
profiles:
# CORRECT:
spring:
port: 8080
---
spring:
profiles:
active: dev
# ── PITFALL 7: Forgetting quotes on property references ───────────────
# WRONG — ${} in YAML without quotes is technically fine, but
# some editors misformat it — quote for safety:
spring:
datasource:
password: ${DB_PASSWORD} # works
url: "${DATABASE_URL}" # safer with quotesProperties vs YAML — Side by Side
A direct comparison showing when YAML's structure provides real value over flat properties — and when it doesn't.
yaml
# ── FLAT PROPERTIES (repetitive prefixes): ───────────────────────────
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=20000
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
# ── EQUIVALENT YAML (hierarchical — no prefix repetition): ────────────
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: secret
hikari:
maximum-pool-size: 10
minimum-idle: 5
connection-timeout: 20000
jpa:
hibernate:
ddl-auto: validate
show-sql: false
open-in-view: false
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
# For deep nesting (JPA, Hibernate, Actuator): YAML wins clearly
# For shallow config (single-level properties): .properties is simpler
# ── CHOOSE PROPERTIES WHEN: ───────────────────────────────────────────
# - Team is more comfortable with properties format
# - Configuration is mostly shallow (few nested levels)
# - You frequently append single values
# - You want to avoid YAML indentation errors
# ── CHOOSE YAML WHEN: ─────────────────────────────────────────────────
# - Configuration has deep nesting (datasource, JPA, security)
# - You use multi-document profiles (--- separators)
# - You need lists or maps in configuration
# - Team prefers the structured format
# ── MIXING IS POSSIBLE BUT NOT RECOMMENDED: ───────────────────────────
# Spring Boot can read both application.properties AND application.yml
# Properties takes precedence if both exist for the same key
# Stick to one format per project for consistency