YAML Anchors and Aliases: DRY Configuration Patterns
Repeating the same configuration across multiple sections of a YAML file violates the DRY (Don't Repeat Yourself) principle and creates maintenance headaches. YAML anchors and aliases solve this by allowing you to define a value once and reference it multiple times.
Basic Syntax
Anchor (&): Marks a value for reuse
Alias (*): References an anchored value
# Define an anchor
defaults: &default_settings
timeout: 30
retries: 3
log_level: info
# Use aliases to reference it
development:
<<: *default_settings
log_level: debug
production:
<<: *default_settings
retries: 5
The << merge key incorporates all key-value pairs from the referenced anchor. Properties defined after the merge override the anchored values.
Result after resolution:
development:
timeout: 30
retries: 3
log_level: debug # overridden
production:
timeout: 30
retries: 5 # overridden
log_level: info
Anchor Types
Scalar Anchors
Reuse a single value:
max_connections: &max_conn 100
database:
pool_size: *max_conn
cache:
pool_size: *max_conn
Sequence Anchors
Reuse entire lists:
common_ports: &ports
- 80
- 443
web_server:
ports: *ports
load_balancer:
ports: *ports
Mapping Anchors
Reuse entire objects (the most common pattern):
logging: &log_config
driver: json-file
options:
max-size: "10m"
max-file: "3"
services:
api:
logging: *log_config
worker:
logging: *log_config
The Merge Key (<<)
The merge key has specific behavior:
- It copies all key-value pairs from the referenced mapping
- Explicitly set keys take priority over merged keys
- Multiple merges are processed in order (first wins for conflicts)
# Multiple merges
base: &base
a: 1
b: 2
extra: &extra
b: 3
c: 4
combined:
<<: [*base, *extra]
# Result: a=1, b=2 (base wins), c=4
Real-World Examples
Docker Compose
x-common: &common
restart: unless-stopped
networks:
- app-network
logging:
driver: json-file
options:
max-size: "10m"
services:
api:
<<: *common
image: myapp/api:latest
ports:
- "8080:8080"
environment:
DATABASE_URL: postgres://db:5432/myapp
worker:
<<: *common
image: myapp/worker:latest
environment:
QUEUE_URL: redis://cache:6379
scheduler:
<<: *common
image: myapp/scheduler:latest
Docker Compose uses the x- prefix convention for extension fields that hold anchors. See our YAML for Docker Compose guide for more patterns.
GitHub Actions
jobs:
test:
runs-on: ubuntu-latest
env: &common_env
NODE_VERSION: '20'
CI: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm test
build:
runs-on: ubuntu-latest
needs: test
env:
<<: *common_env
BUILD_TARGET: production
steps:
- uses: actions/checkout@v4
- run: npm run build
Kubernetes
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
resources: &resources
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
- name: sidecar
resources: *resources # Same resource limits
Limitations and Pitfalls
1. No Cross-File References
Anchors only work within a single YAML file. You cannot reference an anchor defined in another file. For cross-file reuse, use templating tools like Helm, Jsonnet, or Kustomize.
2. No Partial Overrides in Sequences
You cannot merge and partially override a list β you replace the entire list:
base_ports: &ports
- 80
- 443
service:
ports: *ports # You get exactly [80, 443]
# Cannot add port 8080 to this list via merge
Workaround: Define the extended list separately.
3. Ordering Matters
Anchors must be defined before they are referenced:
# WRONG - alias before anchor
service:
settings: *defaults
defaults: &defaults
timeout: 30
# CORRECT - anchor before alias
defaults: &defaults
timeout: 30
service:
settings: *defaults
4. Not All Tools Support Merge Keys
The << merge key is not part of the core YAML specification β it is a type-specific extension. Most popular YAML parsers support it, but some strict parsers may not.
Validate your YAML anchor usage with our YAML Validator.
FAQ
Are anchors preserved when converting YAML to JSON?
No. When YAML is parsed, anchors and aliases are resolved into their values. The resulting JSON will have the values expanded inline. This means converting to JSON and back will lose the DRY structure. The anchors exist only in the YAML source format.
Can I use anchors with complex nested overrides?
The merge key (<<) only performs a shallow merge β it copies top-level keys from the anchored mapping. Nested objects are replaced entirely, not deep-merged. For deep merge behavior, you need a tool-specific solution (Helm's merge function, custom YAML processors).
Related Resources
- YAML Validator β Validate YAML with anchors and aliases
- YAML Syntax Tutorial β YAML fundamentals
- YAML for Docker Compose β Docker-specific patterns