Hvert prosjekt trenger konfigurasjon, og du har tre hovedvalg: JSON, YAML eller TOML. Jeg har brukt alle tre mye, og hver gjør meg gal på forskjellige måter. Her er min ærlige vurdering av når du bør bruke hva.

JSON: Den universelle soldaten

Du kjenner allerede JSON. Det er overalt. Hvert språk kan parse det. Men la oss være ærlige om svakhetene som konfigurasjonsfil:

  • Ingen kommentarer. Du kan bokstavelig talt ikke forklare hva en innstilling gjør. Det er galskap for en konfigurasjonsfil.
  • Ingen etterfølgende kommaer. Legg til en ny linje på slutten, glem å legge til komma på forrige linje — og konfigen din brekker.
  • Anførselstegn overalt. Hver nøkkel trenger doble anførselstegn: {"port": 8080} i stedet for bare port: 8080.

Til tross for alt dette brukes JSON til konfigurasjon av npm (package.json), TypeScript (tsconfig.json), VS Code (settings.json) og mer. Grunnen? Null tvetydighet. JSON er så strengt at det bare er én måte å tolke det på.

YAML: Vakkert men farlig

YAML ser fantastisk ut. Rent, minimalt, lesbart for mennesker. Men det har noen beryktede feller:

yaml

Det er "Norge-problemet" jeg nevnte i YAML-artikkelen. YAML 1.1 behandler NO, YES, ON, OFF som booleans. Det er fikset i YAML 1.2, men mange parsere bruker fortsatt 1.1-oppførselen som standard.

Så er det innrykk-sensitiviteten. Et eneste feilplassert mellomrom kan fullstendig endre betydningen av filen din — og feilmeldingen vil være forferdelig.

Likevel er YAML standarden for Docker Compose, Kubernetes, GitHub Actions og Ansible. Hvis du er i DevOps/sky-verdenen, er YAML-kompetanse obligatorisk.

TOML: Konfigurasjonsspesialisten

TOML (Tom's Obvious Minimal Language) ble designet spesifikt for konfigurasjon. Det sikter mot å være åpenbart — som betyr at det er (nesten) umulig å feiltolke en TOML-fil.

Slik ser en TOML-konfigurasjon ut:

toml

Ting TOML gjør veldig bra: native dato/tid-typer (created = 2026-03-08T10:30:00Z), ingen innrykksproblemer, kommentarer med #, og en syntaks som er genuint vanskelig å rote til.

Ulempen? Dypt nestede strukturer blir ordrike. TOML er flott for flat-aktige konfigurasjoner, men hvis du trenger fem nivåer med nesting, kan YAML eller JSON være mer lesbart.

TOML brukes av Rust (Cargo.toml), Python (pyproject.toml), Hugo og et økende antall verktøy.

Mine anbefalinger

ScenarioVelgHvorfor
Maskin-generert konfigJSONStrengest og mest kompatibel
DevOps/infrastrukturYAMLØkosystemet forventer det
App-konfigurasjonTOMLKommentarer + minimal tvetydighet
Enkle nøkkel-verdi-innstillingerTOMLRenest for flate konfigurasjoner
Komplekse nestede strukturerYAMLBest nestet syntaks

Bunnlinjen

Samme konfig i alle tre formater

Å se de samme dataene i alle tre formater fremhever virkelig forskjellene. Her er en enkel app-konfigurasjon:

JSON:

json

YAML:

yaml

TOML:

toml

Legg merke til hvordan JSON krever alle de anførselstegnene og krøllparentesene, YAML er mest konsist men er avhengig av innrykk, og TOML finner en mellomvei med eksplisitte seksjonsoverskrifter og ingen innrykksavhengighet.

Vanlige konfigurasjonsfeil

YAML: Utilsiktet typekonvertering. Utover Norge-problemet vil YAML også tolke 3.10 som tallet 3.1 (dropper den etterfølgende nullen), og 1_000 som 1000. Hvis konfigverdiene dine er versjonsstrenger som 3.10, sett dem alltid i anførselstegn: version: "3.10".

JSON: Glemme at rekkefølge ikke betyr noe. JSON-objekter er uordnede ifølge spesifikasjonen. Hvis konfigbehandlingen din avhenger av nøkkelrekkefølge, bygger du på et skjørt fundament. Noen parsere bevarer innsettingsrekkefølge, andre gjør det ikke.

TOML: Forvirring med tabellmatriser. TOML bruker [[doble.klammer]] for tabellmatriser, noe som snubler opp nybegynnere. Slik definerer du flere servere:

toml

Miljøspesifikke konfigurasjoner

Et område der alle tre formatene sliter er håndtering av miljøspesifikke overstyringer (utvikling vs staging vs produksjon). Vanlige løsninger inkluderer:

  • Flere filer: config.base.yaml + config.production.yaml med dyp sammenslåing
  • Miljøvariabelinterpolasjon: Noen YAML-verktøy støtter ${DB_HOST}-syntaks, men det er ikke standard
  • Eksterne verktøy: Doppler, HashiCorp Vault eller sky-native konfigurasjonstjenester

Personlig foretrekker jeg en enkel tilnærming: én konfigurasjonsfil med fornuftige standardverdier, og miljøvariabler for alt som endres mellom miljøer. Alle tre formatene kan lese miljøvariabler på applikasjonsnivå, så selve konfigurasjonsformatet trenger ikke å støtte interpolasjon.

Formatpopularitet etter økosystem

ØkosystemPrimærformatKjente eksempler
JavaScript/Node.jsJSONpackage.json, tsconfig.json, .eslintrc.json
PythonTOMLpyproject.toml, Cargo.toml (Rust)
DevOps/CloudYAMLdocker-compose.yml, k8s-manifester, GitHub Actions
GoTOML/YAMLBegge mye brukt, ingen enkelt standard
.NETJSONappsettings.json (erstattet XML-basert web.config)

Bunnlinjen

Det finnes ikke ett riktig svar. Bruk JSON når du trenger maksimal kompatibilitet. Bruk YAML når økosystemet krever det (Kubernetes kommer ikke til å begynne å akseptere TOML). Bruk TOML når du vil ha kommentarer og minimale overraskelser.

JSONC og JSON5: JSON med støttehjul

OK, så vi har slaktet JSON for ikke å støtte kommentarer og etterfølgende kommaer. Men her er tingen ingen forteller deg: det finnes faktisk varianter av JSON som fikser disse irritasjonene, og du har sannsynligvis brukt en av dem uten å vite det.

Først ut: JSONC (JSON with Comments). Hvis du noen gang har åpnet en tsconfig.json og tenkt "vent, det er kommentarer her... jeg trodde JSON ikke tillot kommentarer?" — ja, det er JSONC. Det er i bunn og grunn JSON, men du kan bruke // enkeltlinjekommentarer og /* */ blokkkommentarer. VS Code bruker JSONC for sine settings.json-, launch.json- og keybindings.json-filer. TypeScripts tsconfig.json er også teknisk sett JSONC, ikke streng JSON.

Slik ser JSONC ut:

jsonc

Så er det JSON5, som går enda lenger. JSON5 lemper på mange av JSONs strengeste regler:

  • Enkle anførselstegn for strenger: {'name': 'Sarah'} — endelig!
  • Etterfølgende kommaer: {"a": 1, "b": 2,} — ikke mer diff-støy
  • Nøkler uten anførselstegn (hvis de er gyldige identifikatorer): {name: "Sarah"}
  • Heksadesimale tall: 0xFF
  • Flerlinjestrenger med backslash-fortsettelse
  • Infinity, -Infinity og NaN som gyldige tall

JSON5 er flott for konfigurasjonsfiler der mennesker er hovedmålgruppen. Noen verktøy støtter det nativt — for eksempel kan Babels .babelrc være JSON5. Men ikke bruk JSON5 for API-svar eller datautveksling. Hele poenget med streng JSON er at alle er enige om formatet. JSON5 er for mennesker, ikke maskiner.

Min tommelfingerregel: hvis et verktøy støtter JSONC eller JSON5, bruk det. Det er bokstavelig talt ingen ulempe med å ha kommentarer i konfigurasjonsfilene dine. Men hvis du skriver et bibliotek som leser konfig, støtt standard JSON først og JSONC/JSON5 som valgfrie tillegg.

YAML-ankere og aliaser: DRY-konfig

Her er YAMLs virkelige killer-funksjon som mange utviklere aldri oppdager: ankere og aliaser. De lar deg definere en konfigurasjonsblokk én gang og gjenbruke den overalt. I bunn og grunn DRY (Don't Repeat Yourself) for konfigurasjonsfiler.

Et anker merkes med &name og et alias refererer til det med *name. Her er et praktisk Docker Compose-eksempel:

yaml

Ser du hva som skjedde? Vi definerte felles innstillinger én gang med &common og trakk dem inn i tre tjenester med <<: *common. Uten ankere ville du kopiert den restart-policyen og loggkonfigurasjonen inn i hver eneste tjeneste. Og når du trenger å endre loggrotasjonen? Ett sted i stedet for tolv.

Du kan også bruke ankere for enklere verdier — ikke bare maps:

yaml

Nå, fallgruvene. Merge-nøkkelen << som gjør ankere virkelig kraftige? Den er egentlig ikke en del av YAML 1.2-spesifikasjonen. Det var en YAML 1.1-typeutvidelse, og selv om de fleste populære parsere fortsatt støtter den, er den teknisk sett ikke standard. Så hvis du bruker en streng YAML 1.2-parser, fungerer kanskje ikke merge-nøkler.

I tillegg fungerer ankere bare innenfor en enkelt fil. Du kan ikke referere til et anker definert i en annen YAML-fil. Og feilmeldingene når du skriver feil alias-navn? Vanligvis noe som "undefined alias" uten noen kontekst om hvor ankeret var ment å være. Klassisk YAML.

TOML-dypdykk: Avanserte funksjoner

De fleste kjenner TOML-grunnleggende — seksjoner med [klammer], nøkkel-verdi-par, kommentarer med #. Men TOML har noen genuint kule funksjoner som ikke får nok oppmerksomhet. La meg vise deg dem.

Prikkede nøkler lar deg definere nestede strukturer uten seksjonsoverskrifter:

toml

Dette er hendig når du bare har et par nestede verdier og ikke vil opprette en hel seksjon for dem.

Inline-tabeller gir deg JSON-aktig kompakt syntaks for små objekter:

toml

Bruk inline-tabeller sparsomt — de kan ikke strekke seg over flere linjer, og de blir uleselige raskt hvis du stapper for mye inn i dem.

Flerlinjestrenger kommer i to varianter, og her er TOML overraskende gjennomtenkt:

toml

Den trippel-siterte grunnstrenger (""") behandler escape-sekvenser, mens den literal versjonen (''') behandler alt som rå tekst. Dette er perfekt for regex-mønstre eller Windows-filstier der du ikke vil at backslasher skal tolkes som escape-sekvenser.

Native dato/tid-typer er noe verken JSON eller YAML håndterer så rent:

toml

Dette er førsteklasses typer i TOML, ikke strenger som later som de er datoer. TOML-parseren din vil gi deg faktiske dato/tid-objekter, ikke strenger du må parse selv.

Hvorfor valgte Rusts Cargo TOML? Fordi Cargo-konfigurasjoner er nøyaktig sweet spot for TOML: moderat nestet, redigert av mennesker, trenger kommentarer og drar nytte av streng typing. Du vil ikke at avhengighetsversjonene dine stille skal tolkes som flyttall (ser på deg, YAML).

Sikkerhetshensyn

OK, dette er seksjonen der ting blir litt skummelt. Hvis du laster konfigurasjonsfiler fra upålitelige kilder — eller selv om du tror du ikke gjør det — trenger du å vite om deserialiseringsangrep.

Paradeeksemplet er PyYAMLs yaml.load(). I eldre versjoner kunne denne uskyldig-utseende funksjonen kjøre vilkårlig Python-kode innebygd i en YAML-fil. Jeg tuller ikke. Sjekk dette:

yaml

Hvis noen smugler dette inn i en YAML-konfig og Python-appen din laster den med yaml.load() i stedet for yaml.safe_load(), vil den bokstavelig talt kjøre den systemkommandoen. Slette alt. Installere en bakdør. Hva enn angriperen vil.

Løsningen er enkel — bruk alltid yaml.safe_load() i Python:

python

PyYAML-dokumentasjonen advarer nå om dette, og nyere versjoner viser en deprecation-advarsel hvis du bruker yaml.load() uten å spesifisere en Loader. Men det finnes fortsatt utallige veiledninger og Stack Overflow-svar som viser den usikre versjonen. Det er en landmine som ligger i åpen dager.

Så er det "billion laughs"-angrepet (også kalt en XML-bombe, men det fungerer på YAML også). Ideen er rekursiv ekspansjon — du definerer entiteter som refererer til andre entiteter, og skaper eksponentiell vekst:

yaml

Hvert nivå multipliserer dataene med 5, så ved nivå 8 eller 9 ser du på gigabyte med data fra noen få linjer YAML. De fleste moderne YAML-parsere har dybde- og ekspansjonsgrenser for å forhindre dette, men det er verdt å vite om.

JSON er iboende sikrere fordi det ikke har noen kjøringssemantikk overhodet. Det er ingen måte å bygge inn kode, ingen typekonstruktører, ingen entitetsekspansjon. En JSON-parser leser bare data — strenger, tall, booleans, matriser og objekter. Det er det. Dette er en av de undervurderte fordelene med JSONs enkelhet. Når sikkerhet betyr noe, er JSONs mangel på funksjoner faktisk en funksjon.

TOML er også ganske trygt — det har ingen kodekjøringsfunksjoner og ingen rekursiv ekspansjon. Men det er mindre kamptestet enn JSON-parsere, så hold TOML-bibliotekene dine oppdatert.

Bunnlinjen: hvis du aksepterer konfigurasjonsfiler fra brukere eller eksterne kilder, er JSON det sikreste valget. Hvis du må bruke YAML, bruk alltid trygge lastefunksjoner og vurder å kjøre en YAML-linter for å fange mistenkelige konstruksjoner.

Virkelige konfigurasjonsfil-eksempler

Teori er flott, men la oss se på faktiske konfigurasjonsfiler du vil møte i den virkelige verden. Jeg har kommentert hver enkelt for å fremheve format-spesifikke mønstre.

GitHub Actions-arbeidsflyt (YAML):

yaml

Her skinner YAML virkelig. GitHub Actions arbeidsflyt-syntaksen ville vært smertefull i JSON — alle de nestede listene og innrykk-baserte strukturen passer naturlig til YAML. Du kan også se hvordan kommentarer hjelper med å forklare matrise-strategien.

Rusts Cargo.toml (TOML):

toml

Legg merke til hvordan Cargo-manifestet bruker inline-tabeller for avhengigheter med funksjoner. [[bin]] dobbeltklammer-syntaksen definerer en tabell-matrise — hver [[bin]]-oppføring legger til et nytt binært mål. TOML holder dette flatt og lesbart uten noen innrykk-spill.

package.json (JSON):

json

Klassikeren. Ingen kommentarer, masse anførselstegn, men hvert verktøy på planeten kan lese det. Det som gjør at package.json fungerer til tross for JSONs begrensninger, er at skjemaet er så kjent — du trenger ikke kommentarer for å forklare hva scripts.build gjør fordi hver JavaScript-utvikler allerede vet det.

.prettierrc (JSON):

json

Enkel, flat nøkkel-verdi-konfig. Ærlig talt ville dette vært litt penere som TOML (kommentarer!) eller til og med JSONC, og Prettier støtter andre formater. Men JSON er standarden, og for noe så enkelt spiller det ikke stor rolle.

Migrering mellom formater

Så du har bestemt at prosjektets konfigurasjonsformat var en feil og du vil bytte. Eller kanskje du henter inn konfig fra et verktøy som bruker et annet format. Uansett trenger du å konvertere mellom TOML, YAML og JSON. La meg fortelle deg, det er ikke alltid så glatt som du håper.

Verktøy for konvertering:

  • yq — Sveitsisk armékniv for YAML. Kan konvertere mellom YAML, JSON, TOML og XML. yq -o=json config.yaml gir deg JSON-utdata. Det er som jq men for YAML.
  • toml-cli og taplo — Kommandolinje-TOML-prosessorer. Taplo er spesielt god for TOML-formatering og validering.
  • Python-enlinjere — I en knipe konverterer python -c "import yaml, json, sys; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))" < config.yaml YAML til JSON. Ikke pent, men det fungerer.
  • Nettkonvertere — For raske engangskonverteringer kan formatene våre hjelpe. Lim inn konfigen din i riktig formatter, rydd opp, og skriv den manuelt om i målformatet.

Når bør du migrere:

  • Teamet ditt gjør stadig YAML-innrykksfeil i CI-konfigurasjoner? Kanskje bytte til TOML reduserer hodepinen.
  • Du trenger kommentarer i en JSON-konfigurasjonsfil? Vurder å migrere til JSONC (hvis verktøyet støtter det) eller TOML.
  • Du bygger et nytt Rust/Python-prosjekt og økosystemet forventer TOML? Ikke kjemp mot det — bruk TOML.

Vanlige fallgruver ved migrering:

YAMLs implisitte dato-parsing vil bite deg. Hvis du har en YAML-verdi som release: 2024-03-08, tolker YAML det som et dato-objekt, ikke en streng. Konverter det til JSON og du kan få "release": "2024-03-08T00:00:00Z" eller "release": "2024-03-08" avhengig av konverteren. Test alltid utdataene dine.

TOMLs strenge typing betyr at du ikke kan ha matriser med blandede typer. I JSON og YAML er [1, "two", true] helt greit. I TOML må hvert element i en matrise være av samme type. Hvis kildedataene dine har blandede matriser, må du omstrukturere.

Og her er den store: kommentarer går tapt. JSON støtter ikke kommentarer, så hvis du konverterer fra TOML eller YAML til JSON, forsvinner alle de nøye skrevne kommentarene dine. I motsatt retning (JSON til YAML/TOML) vil du manuelt legge til kommentarer for å forklare ikke-åpenbare innstillinger, fordi JSON-versjonen absolutt ikke hadde dem.

En ting til — YAMLs ankere og aliaser har ingen tilsvarende i JSON eller TOML. Hvis YAML-konfigen din er avhengig av ankere for DRY-konfig, betyr konvertering til et annet format at du må manuelt duplisere de delte blokkene. Det kan være en betydelig økning i filstørrelse for komplekse konfigurasjoner.

Prøv det selv

Uansett hvilket format du velger, gjør det å holde konfigene velformaterte dem lettere å gjennomgå og feilsøke. Vår TOML Formatter rydder opp i rotete TOML-filer på et øyeblikk. YAML Formatter fikser innrykksproblemer før de forårsaker problemer. Og JSON Formatter gjør selv dypt nestede JSON-konfigurasjoner lesbare med et blikk.