Spring Bootapplication.yml
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 default

Complete 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.0

Profile-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: INFO

YAML 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: DEBUG

YAML 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 quotes

Properties 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