Se você já copiou um bloco YAML de um lugar para outro dentro de um arquivo, você já enfrentou o problema que âncoras e aliases resolvem. Grandes configurações do Kubernetes, arquivos Docker Compose multi-ambiente e pipelines de CI complexos tendem a repetir os mesmos blocos — limites de recursos, variáveis de ambiente, montagens de volume — vezes e mais vezes. O YAML tem uma resposta embutida para isso, e a maioria dos desenvolvedores não sabe que ela existe.

Âncoras (&) e aliases (*) são o mecanismo do YAML para definir um valor uma vez e referenciá-lo em qualquer outro lugar no mesmo arquivo. Pense em uma âncora como declarar uma variável e em um alias como usá-la. A chave de mesclagem (<<) estende isso para mesclagem de objetos — semelhante ao operador spread do JavaScript. Ambas as funcionalidades são definidas na seção de âncoras de nó da especificação YAML 1.2.

Sintaxe Básica de Âncora e Alias

A sintaxe é mínima. Prefixe um valor com &nome para criar uma âncora, depois use *nome em qualquer lugar no documento para referenciá-la:

yaml
# Define the anchor once
default_timeout: &timeout 30

# Reference it multiple times
services:
  api:
    timeout: *timeout      # → 30
  worker:
    timeout: *timeout      # → 30
  scheduler:
    timeout: *timeout      # → 30

Quando um parser YAML lê isso, cada alias resolve para o mesmo valor exato da âncora. Mude a âncora e todos os aliases são atualizados. Sem necessidade de buscar e substituir.

Mesclando Objetos com a Chave <<

A reutilização de escalares é útil, mas o verdadeiro poder vem da mesclagem de blocos de mapeamento inteiros. A chave de mesclagem << absorve todos os pares chave-valor da âncora referenciada no mapeamento atual:

yaml
# Define a base configuration block
base_service: &base
  restart: unless-stopped
  logging:
    driver: json-file
    options:
      max-size: "10m"
      max-file: "3"
  networks:
    - app-network

# Merge it into specific services
services:
  api:
    <<: *base              # merge all keys from base_service
    image: my-api:latest
    ports:
      - "8080:8080"

  worker:
    <<: *base              # same base config
    image: my-worker:latest
    command: ["node", "worker.js"]

  scheduler:
    <<: *base              # and again
    image: my-scheduler:latest
    command: ["node", "cron.js"]

Chaves definidas diretamente no mapeamento substituem chaves da âncora mesclada. Portanto, se base define restart: unless-stopped e o serviço também define restart: no, o valor do nível do serviço prevalece.

Antes e Depois: Docker Compose no Mundo Real

Veja como um arquivo Docker Compose típico multi-serviço parece sem âncoras — cheio de repetição:

yaml
# BEFORE — repetitive and hard to maintain
version: "3.9"
services:
  api:
    restart: unless-stopped
    env_file: .env
    networks: [app-network]
    logging:
      driver: json-file
      options:
        max-size: "10m"
    depends_on:
      - postgres

  worker:
    restart: unless-stopped
    env_file: .env
    networks: [app-network]
    logging:
      driver: json-file
      options:
        max-size: "10m"
    depends_on:
      - postgres

  mailer:
    restart: unless-stopped
    env_file: .env
    networks: [app-network]
    logging:
      driver: json-file
      options:
        max-size: "10m"
    depends_on:
      - postgres

Agora com âncoras e a chave de mesclagem — cada bloco repetido é definido exatamente uma vez:

yaml
# AFTER — DRY and easy to maintain
version: "3.9"

x-common: &common
  restart: unless-stopped
  env_file: .env
  networks: [app-network]
  logging:
    driver: json-file
    options:
      max-size: "10m"
  depends_on:
    - postgres

services:
  api:
    <<: *common
    image: my-api:2.4.1
    ports:
      - "8080:8080"

  worker:
    <<: *common
    image: my-worker:2.4.1
    command: ["node", "worker.js"]

  mailer:
    <<: *common
    image: my-mailer:2.4.1
    command: ["node", "mailer.js"]
Dica profissional: O prefixo x- em campos de extensão (como x-common) é uma convenção do Docker Compose que impede o Compose de tentar analisar o bloco como uma definição de serviço. É ignorado pelo engine do Compose, mas totalmente utilizável como uma âncora YAML.

GitHub Actions: Estratégia de Matrix com Âncoras

Configuração de CI é outro lugar onde as âncoras compensam. Aqui está um workflow do GitHub Actions que reutiliza configurações comuns de etapas em vários jobs:

yaml
name: Build and Test

on: [push, pull_request]

# Shared setup steps
x-setup-steps: &setup-steps
  - uses: actions/checkout@v4
  - uses: actions/setup-node@v4
    with:
      node-version: "20"
      cache: npm
  - run: npm ci

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - *setup-steps
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - *setup-steps
      - run: npm test -- --coverage

  build:
    runs-on: ubuntu-latest
    steps:
      - *setup-steps
      - run: npm run build

Nota: o parser YAML do GitHub Actions suporta âncoras e aliases. No entanto, alguns sistemas de CI (notavelmente o config.yml do CircleCI antes da versão 2.1) tinham sua própria sintaxe de extensão semelhante a âncoras. Sempre verifique a documentação da ferramenta específica.

Kubernetes: Reutilizando Limites de Recursos

Em manifestos Kubernetes, limites de recursos e variáveis de ambiente são candidatos ideais para âncoras. Aqui está um padrão que uso regularmente:

yaml
# Anchors at the top of the file (or in a shared ConfigMap generator)
x-resources:
  small: &resources-small
    requests:
      memory: "64Mi"
      cpu: "50m"
    limits:
      memory: "256Mi"
      cpu: "200m"
  large: &resources-large
    requests:
      memory: "256Mi"
      cpu: "200m"
    limits:
      memory: "1Gi"
      cpu: "1000m"

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  template:
    spec:
      containers:
        - name: frontend
          image: frontend:latest
          resources: *resources-small    # reuse small profile

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  template:
    spec:
      containers:
        - name: api
          image: api:latest
          resources: *resources-large    # reuse large profile

Múltiplas Mesclagens e Prioridade de Substituição

Você pode mesclar de múltiplas âncoras em um único mapeamento. Forneça-as como uma lista sob <<. Entradas anteriores na lista têm prioridade sobre as posteriores para chaves duplicadas:

yaml
defaults: &defaults
  color: blue
  size: medium
  weight: light

overrides: &overrides
  color: red          # will override defaults.color
  weight: heavy       # will override defaults.weight

result:
  <<: [*overrides, *defaults]    # overrides takes priority
  name: widget
# Result: color=red, size=medium, weight=heavy, name=widget

Limitações para Conhecer

  • Somente no mesmo arquivo. Âncoras e aliases só funcionam dentro de um único fluxo de documento YAML. Você não pode referenciar uma âncora de um arquivo diferente. Para reutilização entre arquivos, você precisa do mecanismo próprio da sua ferramenta (ex.: templates do Helm, Kustomize ou processadores YAML como ytt).
  • Sem valores computados. Aliases resolvem para cópias exatas do valor da âncora. Não há interpolação ou lógica de template — isso é para ferramentas como Helm ou Jinja2.
  • A chave de mesclagem é uma extensão YAML. A chave de mesclagem << é definida em uma extensão YAML 1.1, não na especificação principal. A maioria dos parsers a suporta, mas parsers YAML 1.2 estritamente conformes podem não suportar.
  • Referências circulares quebram parsers. Não tente ancorar um nó e depois referenciá-lo dentro de si mesmo. É tecnicamente inválido.
  • Aliases copiam, não referenciam. Modificar um valor de alias resolvido no seu código não altera a âncora ou outros aliases. São valores independentes após o parsing.

Conclusão

Âncoras e aliases YAML são um dos recursos menos utilizados do formato. Em qualquer arquivo YAML com mais de cerca de 50 linhas onde o mesmo bloco de configuração aparece mais de duas vezes, âncoras quase certamente devem estar lá. A diferença de manutenibilidade entre o antes e o depois é dramática — alterar um perfil de limite de recursos ou uma variável de ambiente compartilhada em vez de varrer o arquivo inteiro. Use o Formatador YAML para manter seus arquivos com âncoras organizados, e o Validador YAML para confirmar que suas referências de âncoras são resolvidas corretamente.