YAML anchors and aliases
Large YAML config files repeat themselves: the same database block, the same resource limits, the same labels copied across services. YAML has a built-in way to write a value once and refer to it everywhere, using anchors and aliases. Used well it removes duplication. Used carelessly it opens a denial of service hole.
Anchors and aliases
An anchor labels a node with &name. An alias refers back to it with *name. The alias is not a copy you edit later; it points at the same node.
default: &defaults
adapter: postgres
host: localhost
port: 5432
development:
<<: *defaults
database: app_dev
production:
<<: *defaults
database: app_prod
host: db.internal
Here &defaults names the shared block and *defaults pulls it into each environment. Change a shared value once and every alias reflects it.
Merge keys extend a map
The << key in the example above is the merge key. It takes the keys from the aliased map and folds them into the current map. Keys you write alongside it win, so production overrides host while inheriting everything else. This is the real workhorse for DRY configuration: define a base map, anchor it, then merge it into each variant and override only what differs.
You can merge from several anchors at once by giving the merge key a list:
production:
<<: [*defaults, *prod_secrets]
database: app_prod
Note that the merge key is a widely supported convention rather than part of the core YAML 1.2 spec, so a strict parser may not honor it. Most real-world tools do.
A few practical limits
Anchors are scoped to a single document. You cannot define an anchor in one file and alias it from another, which limits reuse to within one document. Aliases also must appear after their anchor is defined, since a parser reads top to bottom. For sharing across files you need a templating layer on top of YAML, not anchors alone.
The billion laughs risk
Because an alias can be referenced many times, and an anchored node can itself contain aliases, a small file can expand into an enormous structure in memory:
a: &a ["x", "x", "x", "x", "x", "x", "x", "x", "x"]
b: &b [*a, *a, *a, *a, *a, *a, *a, *a, *a]
c: &c [*b, *b, *b, *b, *b, *b, *b, *b, *b]
Each level multiplies the previous one, so a handful of levels reaches billions of nodes. This is the billion laughs attack, and it can exhaust memory and crash a service that parses untrusted YAML. The defense is to parse untrusted input with a parser that limits alias expansion or disables anchors, and never feed user-supplied YAML to a naive loader.
Convert and check your config
When you want to see what a YAML file actually expands to, converting it to JSON resolves every alias and merge, making the final structure explicit. The YAML to JSON converter does this in your browser so the config, which often holds secrets, never leaves your device. For common parsing traps, read YAML gotchas: the Norway problem, and YAML to JSON and back covers round tripping.
The takeaway: use anchors and merge keys to keep config DRY, remember they are document-scoped, and never expand untrusted YAML without limits.