YAML Anchors and Aliases

Updated

Anchors and aliases are YAML's built-in mechanism for reuse. Mark a value with &name once, then reference it anywhere in the same document with *name. Combined with the merge key <<, they let you define defaults in one place and override only what changes, which is exactly what large Docker Compose and CI files need.

Anchors and aliases

defaults: &defaults
  timeout: 30
  retries: 3

service_a:
  settings: *defaults

service_b:
  settings: *defaults

Both services get the same settings mapping. Change the anchored block and every alias follows. An anchor can be attached to any node: a mapping, a list, or a single scalar.

region: &region us-east-1
primary_region: *region
backup_region: *region

Merge keys: <<

An alias replaces a whole value. To inherit keys and then override some, use the merge key:

base: &base
  image: node:20
  restart: unless-stopped
  environment:
    NODE_ENV: production

web:
  <<: *base
  ports:
    - "3000:3000"

worker:
  <<: *base
  command: npm run worker
  restart: "no"     # overrides the merged value

Keys written directly in web and worker take precedence over the merged ones. Note that the merge is shallow: environment is replaced as a whole if you redefine it, not merged key by key.

Merging several anchors at once is allowed with a list; earlier entries win on conflicts:

prod:
  <<: [*base, *prod_overrides]

Real-world examples

Docker Compose

x-logging: &default-logging
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

services:
  api:
    image: myorg/api:1.4.2
    logging: *default-logging
  db:
    image: postgres:16
    logging: *default-logging

Top-level keys starting with x- are extension fields that Compose ignores, making them the conventional home for anchored blocks.

GitLab CI

.node_job: &node_job
  image: node:20
  before_script:
    - npm ci

test:
  <<: *node_job
  script: npm test

lint:
  <<: *node_job
  script: npm run lint

Keys beginning with a dot are hidden jobs in GitLab CI, so they serve as templates without running. GitLab also offers extends:, which does a deep merge and works across included files, so prefer it for anything complex.

Rules and limitations

  • An anchor must be defined before it is referenced, reading top to bottom.
  • Anchors are scoped to one document. They do not cross --- boundaries or files.
  • Anchor names may contain letters, digits, -, and _. Spaces and most punctuation are not allowed.
  • Redefining an anchor name later in the document is legal; aliases after that point use the new value.
  • The merge key << only works on mappings. You cannot merge lists.
  • Not every consumer supports anchors. GitHub Actions rejects them; some strict JSON-schema-based tools expand them but then complain about the duplicated content.

Debugging anchors

The easiest way to see what an alias actually produces is to expand it. Paste the file into the YAML to JSON converter or the YAML parser; both resolve every alias and merge key so you can read the final structure. If the file fails to parse with "unidentified alias", the *name has a typo or is used before its &name.

Frequently asked questions

What is an anchor in YAML?

An anchor is a label attached to a node with &name. Elsewhere in the same document, *name (an alias) refers back to that node, so the value is reused without being copied.

What does << mean in YAML?

<< is the merge key. <<: *base copies every key from the anchored mapping into the current mapping, and keys defined locally override the merged ones. It is not part of YAML 1.2 core but is supported by most parsers, including PyYAML, js-yaml, Docker Compose, and GitLab CI.

Can I use an anchor from another file?

No. Anchors are scoped to a single document. Even within one file, an anchor defined in one --- separated document is not visible in the next.

Do anchors survive conversion to JSON?

No. JSON has no reference concept, so aliases are expanded into copies. The data is identical but the file gets longer. See the YAML to JSON converter.

Does Kubernetes support YAML anchors?

kubectl parses anchors and aliases within a single document. Helm does too, but only inside one template. GitHub Actions does not support anchors at all and will reject the workflow.