Ogni progetto ha bisogno di configurazione, e avete tre opzioni principali: JSON, YAML o TOML. Ho usato tutti e tre estesamente, e ciascuno mi fa impazzire in modi diversi. Ecco la mia opinione onesta su quando usare cosa.
JSON: Il soldato universale
Conoscete già JSON. È ovunque. Ogni linguaggio sa parsarlo. Ma siamo onesti sulle sue debolezze come file di configurazione:
- Niente commenti. Letteralmente non potete spiegare cosa fa un'impostazione. È assurdo per un file di config.
- Niente virgola finale. Aggiungete una riga alla fine, dimenticate la virgola nella riga precedente — config rotta.
- Virgolette ovunque. Ogni chiave ha bisogno di virgolette doppie:
{"port": 8080}invece di semplicementeport: 8080.
Nonostante tutto, JSON è usato per la configurazione da npm (package.json), TypeScript (tsconfig.json), VS Code (settings.json) e altri. Il motivo? Zero ambiguità. JSON è così rigido che c'è solo un modo per interpretarlo.
YAML: Bello ma pericoloso
YAML è magnifico. Pulito, minimale, leggibile per gli umani. Ma ha trappole notorie:
Questo è il "problema della Norvegia" che ho menzionato nell'articolo su YAML. YAML 1.1 tratta NO, YES, ON, OFF come booleani. È stato corretto in YAML 1.2, ma molti parser usano ancora il comportamento 1.1 come predefinito.
Poi c'è la sensibilità all'indentazione. Un singolo spazio fuori posto può cambiare completamente il significato del file — e il messaggio di errore sarà terribile.
Detto questo, YAML è lo standard per Docker Compose, Kubernetes, GitHub Actions e Ansible. Se lavorate nel mondo DevOps/cloud, la padronanza di YAML è obbligatoria.
TOML: Lo specialista della configurazione
TOML (Tom's Obvious Minimal Language) è stato progettato specificamente per la configurazione. Punta ad essere ovvio — il che significa che (quasi) non c'è modo di leggere male un file TOML.
Ecco come appare una config TOML:
Cosa fa davvero bene TOML: tipi nativi data/ora (created = 2026-03-08T10:30:00Z), nessun problema di indentazione, commenti con #, e una sintassi che è genuinamente difficile da sbagliare.
Lo svantaggio? Le strutture profondamente annidate diventano verbose. TOML è ottimo per config piatte, ma se avete bisogno di cinque livelli di annidamento, YAML o JSON potrebbero essere più leggibili.
TOML è usato da Rust (Cargo.toml), Python (pyproject.toml), Hugo e un numero crescente di strumenti.
Le mie raccomandazioni
| Scenario | Scelta | Perché |
| Config generata da macchina | JSON | Più rigoroso e compatibile |
| DevOps/infrastruttura | YAML | L'ecosistema lo richiede |
| Configurazione app | TOML | Commenti + ambiguità minima |
| Impostazioni semplici chiave-valore | TOML | Più pulito per config piatte |
| Strutture annidate complesse | YAML | Migliore sintassi annidata |
In conclusione
La stessa config in tutti e tre i formati
Vedere gli stessi dati in tutti e tre i formati mette davvero in evidenza le differenze. Ecco una semplice configurazione di app:
JSON:
YAML:
TOML:
Notate come JSON richiede tutte quelle virgolette e parentesi graffe, YAML è il più conciso ma dipende dall'indentazione, e TOML trova una via di mezzo con intestazioni di sezione esplicite e nessuna dipendenza dall'indentazione.
Errori comuni nei file di configurazione
YAML: Conversione di tipo accidentale. Oltre al problema della Norvegia, YAML interpreta anche 3.10 come il numero 3.1 (eliminando lo zero finale), e 1_000 come 1000. Se i vostri valori di config sono stringhe di versione come 3.10, metteteli sempre tra virgolette: version: "3.10".
JSON: Dimenticare che l'ordine non conta. Gli oggetti JSON sono non ordinati per specifica. Se l'elaborazione della vostra config dipende dall'ordine delle chiavi, state costruendo su fondamenta fragili. Alcuni parser preservano l'ordine di inserimento, altri no.
TOML: Confusione con gli array di tabelle. TOML usa [[doppie.parentesi]] per gli array di tabelle, cosa che confonde i principianti. Ecco come definire più server:
Config specifiche per ambiente
Un'area in cui tutti e tre i formati hanno difficoltà è la gestione degli override specifici per ambiente (dev vs staging vs produzione). Le soluzioni comuni includono:
- File multipli:
config.base.yaml+config.production.yamlcon merge profondo - Interpolazione di variabili d'ambiente: Alcuni strumenti YAML supportano la sintassi
${DB_HOST}, ma non è standard - Strumenti esterni: Doppler, HashiCorp Vault, o servizi di configurazione cloud-native
Personalmente, preferisco un approccio semplice: un file di config con valori predefiniti sensati, e variabili d'ambiente per tutto ciò che cambia tra gli ambienti. Tutti e tre i formati possono leggere variabili d'ambiente a livello applicativo, quindi il formato di config stesso non ha bisogno di supportare l'interpolazione.
Popolarità del formato per ecosistema
| Ecosistema | Formato principale | Esempi notevoli |
| JavaScript/Node.js | JSON | package.json, tsconfig.json, .eslintrc.json |
| Python | TOML | pyproject.toml, Cargo.toml (Rust) |
| DevOps/Cloud | YAML | docker-compose.yml, manifesti k8s, GitHub Actions |
| Go | TOML/YAML | Entrambi ampiamente usati, nessun singolo standard |
| .NET | JSON | appsettings.json (ha sostituito web.config basato su XML) |
In conclusione
Non c'è un'unica risposta giusta. Usate JSON quando avete bisogno di massima compatibilità. Usate YAML quando l'ecosistema lo richiede (Kubernetes non inizierà ad accettare TOML). Usate TOML quando volete commenti e sorprese minime.
JSONC e JSON5: JSON con le rotelle
Ok, abbiamo criticato JSON per non supportare commenti e virgole finali. Ma ecco cosa nessuno vi dice: esistono in realtà varianti di JSON che risolvono questi fastidi, e probabilmente ne avete già usata una senza rendervene conto.
Per primo: JSONC (JSON with Comments). Se avete mai aperto un tsconfig.json e pensato "aspetta, ci sono commenti qui dentro... pensavo che JSON non permettesse commenti?" — sì, quello è JSONC. È fondamentalmente JSON ma potete usare commenti a riga singola con // e commenti a blocco con /* */. VS Code usa JSONC per i suoi file settings.json, launch.json e keybindings.json. Il tsconfig.json di TypeScript è anche tecnicamente JSONC, non JSON rigoroso.
Ecco come appare JSONC:
Poi c'è JSON5, che va oltre. JSON5 allenta diverse delle regole più rigide di JSON:
- Stringhe con virgolette singole:
{'name': 'Sarah'}— finalmente! - Virgole finali:
{"a": 1, "b": 2,}— niente più rumore nei diff - Chiavi senza virgolette (se sono identificatori validi):
{name: "Sarah"} - Numeri esadecimali:
0xFF - Stringhe multilinea con continuazione tramite backslash
Infinity,-InfinityeNaNcome numeri validi
JSON5 è ottimo per file di config dove gli umani sono il pubblico principale. Alcuni strumenti lo supportano nativamente — ad esempio, il .babelrc di Babel può essere JSON5. Ma non usate JSON5 per risposte API o scambio dati. Il punto del JSON rigoroso è che tutti concordano sul formato. JSON5 è per gli umani, non per le macchine.
La mia regola: se uno strumento supporta JSONC o JSON5, usatelo. Non c'è letteralmente nessuno svantaggio nell'avere commenti nei file di config. Ma se state scrivendo una libreria che legge config, supportate prima il JSON standard e JSONC/JSON5 come extra opzionali.
Ancore e alias YAML: Config DRY
Ecco la vera funzionalità killer di YAML che molti sviluppatori non scoprono mai: ancore e alias. Vi permettono di definire un blocco di config una volta e riutilizzarlo ovunque. In pratica DRY (Don't Repeat Yourself) per i file di config.
Un'ancora si segna con &nome e un alias la referenzia con *nome. Ecco un esempio pratico con Docker Compose:
Vedete cosa è successo? Abbiamo definito le impostazioni comuni una volta con &common e le abbiamo inserite in tre servizi con <<: *common. Senza ancore, copiereste e incollereste quella policy di riavvio e config di logging in ogni singolo servizio. E quando dovete cambiare la rotazione dei log? Un posto invece di dodici.
Potete anche usare le ancore per valori più semplici — non solo per le mappe:
Ora, le insidie. La chiave di merge << che rende le ancore davvero potenti? In realtà non fa parte della specifica YAML 1.2. Era un'estensione di tipo YAML 1.1, e sebbene la maggior parte dei parser popolari la supporti ancora, tecnicamente non è standard. Quindi se usate un parser YAML 1.2 rigoroso, le chiavi di merge potrebbero non funzionare.
Inoltre, le ancore funzionano solo all'interno di un singolo file. Non potete referenziare un'ancora definita in un altro file YAML. E i messaggi di errore quando sbagliate il nome di un alias? Di solito qualcosa come "undefined alias" senza alcun contesto su dove l'ancora avrebbe dovuto essere. Classico YAML.
TOML in profondità: Funzionalità avanzate
La maggior parte delle persone conosce le basi di TOML — sezioni con [parentesi], coppie chiave-valore, commenti con #. Ma TOML ha alcune funzionalità davvero interessanti che non ricevono abbastanza attenzione. Lasciate che vi guidi attraverso di esse.
Chiavi puntate vi permettono di definire strutture annidate senza intestazioni di sezione:
È comodo quando avete solo un paio di valori annidati e non volete creare un'intera sezione per loro.
Tabelle inline vi danno una sintassi compatta in stile JSON per oggetti piccoli:
Usate le tabelle inline con parsimonia però — non possono estendersi su più righe e diventano illeggibili in fretta se ci mettete troppa roba.
Stringhe multilinea vengono in due varianti, e qui TOML diventa sorprendentemente curato:
La stringa base con triple virgolette (""") elabora le sequenze di escape, mentre la versione letterale (''') tratta tutto come testo grezzo. È perfetto per pattern regex o percorsi di file Windows dove non volete che i backslash vengano interpretati come escape.
Tipi nativi data/ora sono qualcosa che né JSON né YAML gestisce così pulitamente:
Questi sono tipi di prima classe in TOML, non stringhe che fingono di essere date. Il vostro parser TOML vi darà veri oggetti data/ora, non stringhe che dovete parsare voi stessi.
Perché Cargo di Rust ha scelto TOML? Perché le config di Cargo sono esattamente il punto ideale per TOML: moderatamente annidate, modificate da umani, hanno bisogno di commenti e beneficiano della tipizzazione rigorosa. Non volete che le versioni delle vostre dipendenze vengano silenziosamente interpretate come float (sto guardando te, YAML).
Considerazioni sulla sicurezza
Ok, questa è la sezione dove le cose diventano un po' spaventose. Se state caricando file di config da fonti non attendibili — o anche se pensate di non farlo — dovete conoscere gli attacchi di deserializzazione.
L'esempio classico è il yaml.load() di PyYAML. Nelle versioni più vecchie, questa funzione dall'aspetto innocente poteva eseguire codice Python arbitrario incorporato in un file YAML. Non scherzo. Guardate:
Se qualcuno infila questo in una config YAML e la vostra app Python lo carica con yaml.load() invece di yaml.safe_load(), eseguirà letteralmente quel comando di sistema. Cancellare tutto. Installare una backdoor. Quello che l'attaccante vuole.
La soluzione è semplicissima — usate sempre yaml.safe_load() in Python:
La documentazione di PyYAML ora avverte di questo, e le versioni più recenti mostrano un avviso di deprecazione se usate yaml.load() senza specificare un Loader. Ma ci sono ancora innumerevoli tutorial e risposte Stack Overflow che mostrano la versione non sicura. È una mina nascosta in bella vista.
Poi c'è l'attacco "billion laughs" (chiamato anche bomba XML, ma funziona anche con YAML). L'idea è l'espansione ricorsiva — definite entità che referenziano altre entità, creando crescita esponenziale:
Ogni livello moltiplica i dati per 5, quindi al livello 8 o 9 state guardando gigabyte di dati da poche righe di YAML. La maggior parte dei parser YAML moderni ha limiti di profondità e espansione per prevenire questo, ma vale la pena saperlo.
JSON è intrinsecamente più sicuro perché non ha alcuna semantica di esecuzione. Non c'è modo di incorporare codice, nessun costruttore di tipo, nessuna espansione di entità. Un parser JSON legge semplicemente dati — stringhe, numeri, booleani, array e oggetti. Questo è tutto. Questo è uno dei vantaggi sottovalutati della semplicità di JSON. Quando la sicurezza conta, la mancanza di funzionalità di JSON è in realtà una funzionalità.
TOML è anche abbastanza sicuro — non ha capacità di esecuzione di codice né espansione ricorsiva. Ma è meno testato in battaglia dei parser JSON, quindi tenete aggiornate le vostre librerie TOML.
In conclusione: se accettate file di config da utenti o fonti esterne, JSON è la scelta più sicura. Se dovete usare YAML, usate sempre funzioni di caricamento sicuro e considerate di eseguire un linter YAML per rilevare costrutti sospetti.
Esempi reali di file di configurazione
La teoria è bella, ma guardiamo file di config reali che incontrerete nella pratica. Ho annotato ciascuno per evidenziare pattern specifici del formato.
Workflow GitHub Actions (YAML):
Qui è dove YAML brilla davvero. La sintassi dei workflow GitHub Actions sarebbe dolorosa in JSON — tutte quelle liste annidate e la struttura basata sull'indentazione si mappa naturalmente su YAML. Potete anche vedere come i commenti aiutano a spiegare la strategia matrix.
Cargo.toml di Rust (TOML):
Notate come il manifesto Cargo usa tabelle inline per le dipendenze con features. La sintassi [[bin]] con doppie parentesi definisce un array di tabelle — ogni voce [[bin]] aggiunge un altro target binario. TOML tiene tutto piatto e leggibile senza giochi di indentazione.
package.json (JSON):
Il classico. Niente commenti, un sacco di virgolette, ma ogni strumento sul pianeta può leggerlo. Quello che fa funzionare package.json nonostante i limiti di JSON è che lo schema è così conosciuto — non servono commenti per spiegare cosa fa scripts.build perché ogni sviluppatore JavaScript lo sa già.
.prettierrc (JSON):
Config semplice di tipo chiave-valore piatta. Onestamente, sarebbe leggermente più carina come TOML (commenti!) o anche JSONC, e Prettier supporta altri formati. Ma JSON è il predefinito, e per qualcosa di così semplice, non fa molta differenza.
Migrazione tra formati
Avete quindi deciso che il formato di config del vostro progetto è stato un errore e volete cambiare. O forse state importando config da uno strumento che usa un formato diverso. In ogni caso, dovete convertire tra TOML, YAML e JSON. Vi dico, non è sempre così liscio come si spera.
Strumenti di conversione:
- yq — Il coltellino svizzero per YAML. Può convertire tra YAML, JSON, TOML e XML.
yq -o=json config.yamlvi dà output JSON. È comejqma per YAML. - toml-cli e taplo — Processori TOML da riga di comando. Taplo è particolarmente buono per la formattazione e validazione TOML.
- One-liner Python — In caso di emergenza,
python -c "import yaml, json, sys; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))" < config.yamlconverte YAML in JSON. Non è elegante, ma funziona. - Convertitori online — Per conversioni rapide una tantum, i nostri formatter possono aiutare. Incollate la vostra config nel formatter appropriato, pulitela e riscrivetela manualmente nel formato di destinazione.
Quando migrare:
- Il vostro team continua a fare errori di indentazione YAML nelle config CI? Forse passare a TOML riduce quei grattacapi.
- Avete bisogno di commenti in un file di config JSON? Considerate la migrazione a JSONC (se lo strumento lo supporta) o TOML.
- State costruendo un nuovo progetto Rust/Python e l'ecosistema si aspetta TOML? Non combattetelo — scegliete TOML.
Insidie comuni nella migrazione:
Il parsing implicito delle date di YAML vi morderà. Se avete un valore YAML come release: 2024-03-08, YAML lo interpreta come un oggetto data, non una stringa. Convertitelo in JSON e potreste ottenere "release": "2024-03-08T00:00:00Z" o "release": "2024-03-08" a seconda del convertitore. Testate sempre il vostro output.
La tipizzazione rigorosa di TOML significa che non potete avere array di tipi misti. In JSON e YAML, [1, "two", true] è perfettamente valido. In TOML, ogni elemento di un array deve essere dello stesso tipo. Se i vostri dati sorgente hanno array misti, dovrete ristrutturare.
E qui c'è il punto grosso: i commenti si perdono. JSON non supporta commenti, quindi se convertite da TOML o YAML a JSON, tutti i vostri commenti accuratamente scritti scompaiono. Andando nell'altra direzione (JSON a YAML/TOML), vorrete aggiungere manualmente commenti per spiegare impostazioni non ovvie, perché la versione JSON certamente non li aveva.
Un'altra cosa — le ancore e gli alias di YAML non hanno equivalenti in JSON o TOML. Se la vostra config YAML si basa su ancore per config DRY, convertire in un altro formato significa che dovrete duplicare manualmente quei blocchi condivisi. Questo può essere un'espansione significativa nella dimensione del file per config complesse.
Provatelo voi stessi
Qualunque formato scegliate, mantenere le vostre config ben formattate le rende più facili da esaminare e debuggare. Il nostro TOML Formatter ripulisce file TOML disordinati all'istante. Il YAML Formatter corregge i problemi di indentazione prima che causino problemi. E il JSON Formatter rende leggibili a colpo d'occhio anche le config JSON profondamente annidate.