YAML Anchors and Aliases: Reducing Duplication Without a Templating Engine
Learn how YAML anchors (&) and aliases (*) eliminate copy-paste in configuration files, with a worked example, merge-key limits, and parser verification steps.
01 Sept 2026, 20:51 UTC

The copy-paste problem in large manifests
Large Docker Compose files, Kubernetes manifests, and CI configurations often repeat the same logging driver, resource requests, or environment defaults across many services. When one value changes, every copy must be edited, and drift creeps in. The useful takeaway: YAML anchors and aliases let you define a block once and reference it elsewhere, but they are resolved during parsing and behave differently from templates.
How anchors and aliases work
An anchor (&name) tags a YAML node. An alias (*name) reuses that node later in the same document. The merge key (<<) copies the top-level keys of an aliased map into the current map. These are language features, not string substitution: the parser expands them before your application or orchestrator sees the data.
A worked configuration example
The following app-config.yaml defines shared defaults with an anchor, then reuses them in two services. The same mechanism applies to Kubernetes manifests and Compose files.
# app-config.yaml
defaults: &defaults
timeout: 30
retries: 3
logging:
level: info
format: json
database:
host: localhost
pool: 10
services:
api:
<<: *defaults
timeout: 60
worker:
<<: *defaults
database:
host: db.internal
In this example, api inherits every default but overrides timeout to 60. The worker service inherits all defaults, but its explicit database map replaces the anchored one entirely. The result is database.host: db.internal with no database.pool key, because the merge key performs a shallow merge, not a deep one.
What the parser actually does
When a parser reads *defaults, it replaces the alias with the exact node tagged by &defaults. If that node is a map, the application receives a map with the same keys and values. There is no lazy evaluation or conditional logic: if the anchored node changes, every alias reflects that change because they are the same parsed object.
Limits and common mistakes
Forward references are impossible
An anchor must appear before its alias in the document. You cannot define an alias at the top and anchor it further down.
Merge keys are shallow
The << operator merges only the top-level keys of the referenced map. Nested maps are replaced wholesale, not deep-merged. If you need deep merging, you must either flatten the structure or use a tool that supports it.
Shared references can surprise you
In languages that map YAML nodes to mutable objects—Python dictionaries, Ruby hashes—an alias may produce a reference to the same object rather than a copy. Mutating one service's logging map in code could alter another service that used the same alias. Parsers that build immutable structures or structs (for example, Go's yaml.v3 into structs) copy the data, but you should not rely on this across languages.
Document boundaries block aliases
Anchors do not cross --- document separators. Each YAML document is parsed independently.
Version and parser differences
The merge key << is part of YAML 1.1. YAML 1.2 removed it from the core spec, though many 1.2 parsers still support it as an extension. Kubernetes tooling, Docker Compose, and CI systems may use different parser libraries, so a file that works locally might fail in a pipeline. Always verify with the exact tool that will consume the manifest.
Verifying the expansion
Before committing a heavily anchored file, parse it and inspect the result. On a Linux or macOS workstation with Python 3 and PyYAML installed, run the following from the directory containing the file:
python3 -c "import yaml; print(yaml.safe_load(open('app-config.yaml')))"Replace app-config.yaml with your filename. You need read access to the file. The expected check is that the output contains fully expanded maps with no & or * keys. The worker service should show database.host: db.internal and should not contain database.pool unless you explicitly set it. If the output looks wrong, test with a second parser such as ruamel.yaml or the YAML library built into your target platform. A tool like yamllint can confirm syntax, but it does not always validate merge semantics.
When to reach for something else
Anchors excel at small, stable repetition: default labels, resource requests, probe definitions, or logging blocks. They are the wrong tool for conditional logic, loops, or environment-specific overrides. If you find yourself needing if statements or computed values, use a purpose-built templating layer such as Helm, Kustomize, Jsonnet, or a simple script that generates YAML.
Engineering decision
Treat anchors as a local DRY mechanism within a single file. Keep the anchored blocks small and semantically identical across uses. If the shared block starts to diverge or requires conditional assembly, stop anchoring and switch to explicit duplication or a templating tool. The goal is a manifest that a reviewer can read top-to-bottom without mentally resolving a graph of aliases.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.