YAML Anchors, Aliases, and Merge Keys: When DRY Helps and When It Hurts
YAML anchors and aliases let you deduplicate configuration inside a single file, but the merge key << is a non‑standard extension with uneven parser support. Use anchors for small, local reuse; switch to Helm, Kustomize, or Jsonnet when sharing across files or teams.
26 Oct 2025, 14:49 UTC

The duplication problem in deployment manifests
Teams that manage Kubernetes, Docker Compose, or CI/CD pipelines often copy the same block of labels, resource limits, or sidecar definitions across dozens of files. The result is a maintenance burden: a change to a shared label means editing every file, and reviewers must verify that each copy stayed in sync.
YAML’s built‑in &anchor / *alias mechanism and the widely used merge key << promise a single source of truth inside one document. The takeaway: use anchors for small, static reuse inside a single file; reach for a templating tool (Helm, Jsonnet, Kustomize) when the reuse spans files or requires logic.
Anchors and aliases in practice
An anchor marks a node so it can be referenced later. An alias expands to the exact same node in the parsed tree. Because the alias points to the original node, any later modification of that node (via a merge) affects every reference.
# base-deployment.yaml
base: &base
replicas: 3
labels:
app: myapp
tier: frontend
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "200m"
memory: "128Mi"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-prod
spec:
replicas: *base.replicas # scalar alias
selector:
matchLabels: *base.labels # map alias
template:
metadata:
labels: *base.labels
spec:
containers:
- name: app
image: myorg/app:1.2.3
resources: *base.resources
Parsing this with any YAML 1.2‑compliant library (SnakeYAML, PyYAML, ruamel.yaml, Go’s yaml.v3) yields a single replicas integer, one labels map, and one resources map shared across the document. Changing base.replicas to 5 updates both the top‑level spec.replicas and any other alias that points to it.
The merge key << and its portability limits
The merge key lets you combine a base mapping into another mapping, overriding or adding keys. It is a YAML 1.1 extension, not part of the 1.2 core, so support varies:
- PyYAML and ruamel.yaml enable it by default.
- SnakeYAML supports it when the
LoaderOptionsflagsetAllowDuplicateKeys(true)is set (older versions required a custom constructor). - Go yaml.v3 implements merge keys out of the box.
- Some security‑hardened parsers (e.g.,
yaml.v3withDecodeOptions{DisallowAlias: true}) disable aliases entirely, which also disables<<.
Example using merge:
base: &base
replicas: 3
labels:
app: myapp
tier: frontend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-staging
spec:
<<: *base # merge base into spec
replicas: 2 # override only replicas
template:
metadata:
labels:
<<: *base.labels
env: staging # add a new label
After parsing, spec contains replicas: 2, labels.app, labels.tier, and the extra labels.env. The merge is shallow; nested maps (like resources) are not recursively merged unless you anchor each level explicitly.
When anchors become a liability
- Readability and diffs: A
git diffshows only the anchor definition change, not every expanded location. Reviewers unfamiliar with YAML references may miss the impact. - Hidden coupling: Changing an anchored map affects every alias, which can cause unintended side‑effects in large manifests.
- Security parsers: If your pipeline ingests untrusted YAML (e.g., user‑supplied Helm values), many parsers default to disabling aliases to prevent billion‑laughs‑style expansion attacks. You must explicitly enable them, adding operational complexity.
- Cross‑file reuse: Anchors only work within a single document (or a single YAML stream if you use
---separators). Sharing across repositories still requires a templating layer.
Practical verification checklist
- Write a minimal snippet with
&baseand*baseand parse it with the exact library version your CI uses. Confirm the output structure matches expectations (e.g.,yaml.dump(parsed)shows duplicated keys only once). - Run the same snippet through a second parser (e.g., Python ruamel.yaml and Go yaml.v3). Compare the serialized output; divergent handling of
<<will appear as missing or extra keys. - Check parser release notes or source for alias‑related security flags. In Go,
yaml.DecodeOptions{DisallowAlias: true}is the toggle; in SnakeYAML,LoaderOptions.setAllowAliases(false). - Generate a manifest with anchors and another without, then diff them with
diff -uor a structured YAML diff tool (e.g.,dyff). If the diff is noisy, consider moving the shared block to a template.
Decision guide
| Scenario | Recommended approach |
|---|---|
| Few repeated keys inside one file (labels, resource limits) | Anchors + aliases |
| Need to override a subset of a base map | Merge key << (verify parser support) |
| Shared configuration across many files or repos | Helm charts, Kustomize bases, or Jsonnet libraries |
| Untrusted input or strict security policy | Disable aliases; use external templating instead |
Bottom line: YAML’s native reuse mechanisms are powerful for keeping a single manifest tidy, but they stop scaling once the same base must travel across files or teams. Treat anchors as a local DRY tool, and adopt a dedicated templating solution the moment you feel the need to include or import a base from another location.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.