Use YAML Anchors & Merge Keys to Keep Your Configs DRY (and Safe)
YAML anchors and merge keys let you define a base configuration once and reuse it across environments, cutting duplication and reducing errors. This post walks through a concrete example, explains how merge works, and highlights pitfalls to avoid.
18 Jul 2025, 10:33 UTC

Problem: Duplicate Environment Configs
When a project supports multiple environments—dev, staging, prod—configuration files often look almost identical. A small change in one file can slip through, causing subtle bugs. Manual duplication also bloats the repository and makes onboarding harder.
Solution: Anchors (&) and Aliases (*)
YAML lets you anchor a block of key‑value pairs with &name and later reference it with an alias *name. The parser expands the alias into a copy of the anchored block, so you write the block once and reuse it anywhere in the same document.
Example:
database: &db_base
host: <YOUR_DB_HOST>
port: 5432
user: <YOUR_DB_USER>
password: <YOUR_DB_PASSWORD>
timeout: 30
# dev uses the base exactly
dev:
database: *db_base
# prod overrides only timeout
prod:
database:
<<: *db_base
timeout: 120
Here &db_base defines the common database settings. The dev section simply copies them. The prod section uses the merge key (<<) to inherit the base map but replace timeout with a higher value.
Merge Key Mechanics (<<)
The << key is a YAML 1.1 feature that merges one or more maps into the current map. When the merge target contains an alias, the parser first resolves the alias, then copies all its keys into the child map. If a key already exists in the child, the child’s value wins.
Key points:
- Only works with maps (not scalars).
- Supports a list of aliases:
<<: [*a, *b]mergesathenb, with later entries overriding earlier ones. - Not part of strict YAML 1.2; some parsers require a flag or extension.
Practical Example: Multi‑Environment Web App
Suppose you have a web service that needs different logging levels and database URLs per environment. Below is a self‑contained YAML snippet you could drop into config.yaml and parse with any modern library (PyYAML, SnakeYAML, js-yaml).
# Base logging settings
logging: &log_base
level: INFO
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# Base database settings
db: &db_base
host: <DB_HOST>
port: 3306
user: <DB_USER>
password: <DB_PASS>
pool_size: 10
# Development environment
dev:
logging: *log_base
db: *db_base
debug: true
# Staging environment
staging:
logging:
<<: *log_base
level: DEBUG
db: *db_base
debug: false
# Production environment
prod:
logging:
<<: *log_base
level: WARN
file: /var/log/app.log
db:
<<: *db_base
host: prod-db.company.com
pool_size: 50
After parsing, the prod.logging map will contain level=WARN, format=…, and file=/var/log/app.log. The prod.db map will copy all keys from db_base but replace host and pool_size.
Trade‑offs & Limitations
Readability: New developers must jump between anchor definitions and aliases. A file with many anchors can feel fragmented.
Parser support: While most popular libraries support anchors, the merge key is optional in YAML 1.2. If you target a strict 1.2 parser, you may need to enable the !!merge tag or avoid << entirely.
Circular references: Defining an alias that points back to itself (directly or indirectly) can cause parser errors or infinite loops. Check your parser’s error handling; some emit a clear RecursionError, others may hang.
Tooling: Some CI tools that lint or transform YAML may not understand anchors, leading to false positives. Verify that your pipeline passes through the raw YAML unchanged.
Actionable Takeaway
1. Identify blocks of configuration that are identical across environments—databases, logging, feature flags.
2. Anchor those blocks once with &name.
3. Reuse them with *name or merge with <<: *name for overrides.
4. Test the final parsed object by loading the YAML in your language’s library and inspecting the resulting map. For example, in Python:
import yaml
cfg = yaml.safe_load(open("config.yaml"))
print(cfg["prod"]["db"]) # should show merged values
5. Document the anchor usage in your README so newcomers understand the structure.
By anchoring common settings and merging only what differs, you reduce duplication, lower the chance of environment drift, and keep your configuration DRY.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.