Configuration, Profiles & Actuator

Working with YAML

18 min Lesson 4 of 13

Working with YAML

Spring Boot supports two configuration file formats out of the box: the classic application.properties (key=value pairs) and the more expressive application.yml (YAML). Both files are loaded automatically from the classpath root — you do not need any extra dependency or annotation to switch. Understanding the structure of YAML and the trade-offs between the two formats is an essential skill for any professional Spring Boot developer.

YAML Fundamentals in Under Five Minutes

YAML (YAML Ain't Markup Language) represents data as indented key-value pairs, lists, and maps. Spring's YAML support is provided by SnakeYAML, which is already on the classpath whenever you include spring-boot-starter.

The core rules you need to know:

  • Indentation defines nesting. Use spaces, never tabs. Two spaces per level is the universal convention in Spring projects.
  • Keys and values are separated by a colon followed by a space (: ).
  • Lists use a leading dash (- ).
  • Strings can be unquoted unless they contain special characters (: { } [ ] , # & * ? | > ' " % @ `).
  • Boolean values are true / false (lowercase).
YAML is a superset of JSON. Any valid JSON document is also valid YAML, but the reverse is not true. In practice you will always write YAML in its indented block style, not JSON style.

Flat Properties vs. Nested YAML — Side by Side

Consider a typical database and server configuration. In application.properties every key is fully qualified:

server.port=8080 server.servlet.context-path=/api spring.datasource.url=jdbc:postgresql://localhost:5432/inventory spring.datasource.username=appuser spring.datasource.password=secret spring.datasource.hikari.maximum-pool-size=10 spring.jpa.show-sql=false spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

The exact same configuration in application.yml:

server: port: 8080 servlet: context-path: /api spring: datasource: url: jdbc:postgresql://localhost:5432/inventory username: appuser password: secret hikari: maximum-pool-size: 10 jpa: show-sql: false properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect

Spring's PropertySourcesPlaceholderConfigurer and the Environment abstraction flatten YAML into the same dot-notation keys internally, so @Value("${server.port}") and @ConfigurationProperties(prefix = "spring.datasource") work identically regardless of which file format you chose.

Lists in YAML

In properties files, lists use indexed keys: app.allowed-origins[0]=https://example.com. In YAML the same list reads naturally:

app: allowed-origins: - https://example.com - https://staging.example.com - http://localhost:3000 # Inline (flow) style — equivalent, useful for short lists roles: - ADMIN - USER - VIEWER

When bound to a @ConfigurationProperties bean, Spring maps the YAML list directly to a List<String> field.

Multi-Document YAML Files

A single application.yml can contain multiple documents separated by ---. Each document can activate under a specific profile:

# Default / base configuration spring: datasource: url: jdbc:h2:mem:devdb username: sa password: "" jpa: show-sql: true --- spring: config: activate: on-profile: production datasource: url: jdbc:postgresql://prod-db:5432/inventory username: ${DB_USER} password: ${DB_PASS} jpa: show-sql: false

The first document supplies defaults for every environment. The second document overrides only the datasource and JPA keys when the production profile is active. This is one of YAML's strongest selling points: you can consolidate what would otherwise be three separate files (application.properties, application-dev.properties, application-prod.properties) into a single readable file.

Prefer separate profile files over multi-document YAML for large applications. Consolidation is convenient for small projects, but a single 300-line YAML with five profile documents becomes hard to review in pull requests. The application-{profile}.yml pattern (one file per profile) scales better and keeps secrets-containing files isolated.

YAML Anchors and Aliases — Reduce Repetition

YAML supports anchors (&name) and aliases (*name) that let you reuse a block without repeating it. This is a YAML-only feature with no equivalent in properties files:

# Define a reusable block once logging-defaults: &logging-defaults level: root: INFO org.springframework: WARN com.example: DEBUG --- spring: config: activate: on-profile: staging logging: <<: *logging-defaults # merge all keys from the anchor file: name: /var/log/app-staging.log --- spring: config: activate: on-profile: production logging: <<: *logging-defaults file: name: /var/log/app-prod.log
Spring Boot does not fully support YAML merge keys (<<:) in all contexts. SnakeYAML resolves anchors before handing the data to Spring's binder, so simple value anchors work reliably. Merge-key anchors (<<:) work for logging and custom properties, but avoid using them inside spring.* or server.* blocks — Spring's relaxed binding can occasionally misinterpret merged maps. Test thoroughly if you use this feature for critical configuration.

When to Prefer YAML Over Properties

Neither format is objectively superior — the choice is a matter of fit:

  • Choose YAML when you have deeply nested configuration (e.g. Spring Security, Spring Cloud Gateway route definitions, complex Hikari tuning), when your team already reads YAML fluently from Kubernetes or Docker Compose, or when you want multi-document profile consolidation in a single file.
  • Choose Properties when configuration is shallow and few, when the file will be processed by external tools that parse key=value (some legacy CI/CD pipelines), or when team members are unfamiliar with YAML's indentation sensitivity.
  • Never mix both for the same application. If application.yml and application.properties both exist, Spring Boot loads both but application.properties wins in case of conflict — a silent, confusing precedence rule that causes hard-to-diagnose bugs.

Common YAML Pitfalls

YAML's flexibility hides several traps that bite developers once and are never forgotten:

  • Tabs vs. spaces: A tab character in YAML is a parse error. Configure your editor to expand tabs to spaces in .yml files.
  • Norway Problem: Bare NO is parsed as false in older YAML 1.1 (used by SnakeYAML). Always quote country codes: country: "NO". Spring Boot 2.4+ upgraded to SnakeYAML 1.28 which follows YAML 1.1 but the pitfall still exists with on, off, yes, no.
  • Colons in values: url: http://localhost:8080 is valid because there is a space after the colon. But message: Hello: World breaks parsing — quote it: message: "Hello: World".
  • Missing space after colon: port:8080 is treated as a string key with value null, not as port = 8080.

Summary

YAML brings hierarchical clarity to Spring Boot configuration. The indented block format eliminates the tedious repetition of shared prefixes, lists bind naturally, and multi-document files let you co-locate profile overrides. Spring Boot's YAML support is zero-configuration — add application.yml to src/main/resources and it is picked up automatically. Watch out for indentation errors, bare boolean-like strings, and the tab trap. In the next lesson you will learn how to keep sensitive values out of both formats entirely, using environment variables and secrets managers.