05: Anchor, alias, merge key e chiavi
← 04 - Tipi, risoluzione implicita e trappole · Indice · successivo → 06 - YAML nella pratica
5.1 Anchor e alias: non ripetersi
Un anchor (&nome) etichetta un nodo; un alias (*nome) lo richiama.
default: &impostazioni
restart: unless-stopped
logging:
driver: json-file
servizio_a:
<<: *impostazioni
image: nginx
servizio_b: *impostazioniRegole dalla specifica:
- L’alias si riferisce all’anchor precedente più vicino. Un anchor può essere ridefinito più avanti nel file e da quel punto gli alias puntano al nuovo valore.
- Un alias non può avere proprietà o contenuto propri:
*baserestituisce esattamente quel nodo. Non esiste un “alias con override”, per quello serve la merge key. - Gli anchor valgono per documento: non attraversano i
---e, soprattutto, non attraversano i file. Non esiste un “anchors.yaml” incluso e riusato altrove. - Il nome dell’anchor non può contenere
, [ ] { }.
Dettaglio che conta: gli alias condividono l’oggetto, non lo copiano. ✅ verificato in
Python: due elementi creati da alias sono lo stesso oggetto in memoria (is → True).
Se il programma che legge muta uno, mutano tutti. È anche la base dell’attacco “billion
laughs” (07 - Strumenti, sicurezza, debug e reference).
5.2 Merge key <<
base: &base
a: 1
b: 2
derivato:
<<: *base
b: sovrascritto
c: 3✅ verificato → {'a': 1, 'b': 'sovrascritto', 'c': 3}
Due regole di precedenza da tenere distinte:
- Le chiavi scritte esplicitamente vincono sempre sul merge.
- Con più sorgenti,
<<: [*A, *B], vince la prima. ✅ verificato: conbase = {a:1, b:2}ebig = {b:99, c:3},<<: [*base, *big]dàb: 2, mentre<<: [*big, *base]dàb: 99.
Il punto 2 è l’opposto di quello che fanno Object.assign in JS e dict.update in
Python, dove vince l’ultimo. È una fonte di bug garantita se non lo sai.
<<non è nella specifica YAML 1.2È stato rimosso nel 2009 insieme al resto della libreria di tipi 1.1. Sopravvive come estensione dei parser, e ad agosto 2026 la situazione è questa:
Parser <<attivo di defaultPyYAML sì ruamel.yaml (round-trip) sì js-yaml 5 no yaml(npm) 2.xno ✅ verificato: con uno schema 1.2 core,
<<: *basenon fa il merge: diventa una chiave letterale'<<'con dentro la mappa. Nessun errore, dati sbagliati. Un file che usa<<e passa da un tool Python a uno JavaScript si rompe in silenzio.
Aggiungi che nel 2025-2026 il merge di js-yaml ha generato due avvisi di sicurezza
(prototype pollution e complessità quadratica), ed è ragionevole concludere: << è
comodo, ma usalo solo dove sei certo del parser.
5.3 Quando gli anchor sono la scelta giusta
Sono un meccanismo di riuso testuale, non un sistema di ereditarietà. Funzionano bene per:
- valori ripetuti nello stesso file (una versione, un percorso, un’immagine Docker);
- blocchi di configurazione identici (logging, restart policy, healthcheck).
Funzionano male quando:
- la struttura da riusare sta in un altro file (non si può);
- ti serve override profondo (il merge è superficiale: sostituisce l’intera chiave di primo livello, non fa merge ricorsivo);
- vuoi merge di liste: non è previsto, il merge vale solo per i mapping.
Quando raggiungi quei limiti, la risposta non è forzare YAML: è generare il file con
uno strumento (script, Helm, Kustomize, un template) o usare i meccanismi di composizione
dell’applicazione (!include in Home Assistant, extends in Docker Compose, i reusable
workflow di GitHub Actions).
5.4 Un esempio realistico
x-comune: &comune
restart: unless-stopped
environment: &env-comune
TZ: Europe/Rome
PUID: '1000'
logging:
driver: json-file
options:
max-size: 10m
services:
app:
<<: *comune
image: 'ghcr.io/esempio/app:1.10'
ports:
- '8080:80'
worker:
<<: *comune
image: 'ghcr.io/esempio/app:1.10'
command: ['worker']Nota due cose: il prefisso x- per le chiavi “di servizio” (Docker Compose le ignora
ufficialmente) e le virgolette su '1.10', '1000' e '8080:80': tutti valori che senza
apici cambierebbero tipo (04 - Tipi, risoluzione implicita e trappole).
5.5 Chiavi: i casi limite
Duplicate. La specifica: errore. PyYAML: silenzio, vince l’ultima. Già visto in
02 - Struttura - documenti, mapping, indentazione, ma vale la ripetizione perché è il
bug più frequente in assoluto. Attiva key-duplicates in yamllint.
Non stringa. ✅ verificato: 1: uno e true: booleano nello stesso mapping, letti da
Python, danno {1: 'booleano'}, perché in Python True == 1. YAML le considera chiavi
distinte, Python no. Il dato sparisce senza avviso.
Molto lunghe. Una chiave implicita non può superare i 1024 caratteri né stare su più righe. Se ti serve di più, esiste la sintassi esplicita:
? |
una chiave
su più righe
: il suo valoreSe ti trovi ad averne bisogno, quasi sempre il modello dei dati è sbagliato.
Ordine. YAML non garantisce che l’ordine delle chiavi sia significativo. Molti parser lo preservano (Python dalla 3.7 mantiene l’ordine di inserimento), ma non contarci come parte del contratto.
Esercizi
- Scrivi un
docker-compose.ymlcon tre servizi che condividono logging e restart policy via anchor. Poi verifica condocker compose configche l’espansione sia quella attesa. - Prova
<<: [*A, *B]e poi<<: [*B, *A]con una chiave in comune: constata di persona che vince la prima. - Leggi lo stesso file con PyYAML e con js-yaml e confronta il risultato del merge.
- Prova a usare un anchor definito in un file dentro un altro file incluso: guarda l’errore, così non ci riproverai fra sei mesi.