Ta opp et hvilket som helst Rust-prosjekt og du finner en Cargo.toml. Klon et GitHub-repo og
du finner en .github/workflows/-mappe full av YAML. Begge formater gjør den samme
overfladiske jobben — lagrer strukturert konfigurasjon som mennesker redigerer — men de gjør veldig forskjellige
avveininger. Hvis du noen gang har opplevd at YAML stille og rolig forvrenger en verdi for deg, eller undret deg over
hvorfor Rust valgte TOML i stedet for YAML for sin pakkemanifest, er denne artikkelen for deg.
Kjernforskjellen: Eksplisitt vs Implisitt
Den grunnleggende splittelsen mellom TOML og YAML handler om hvor mye parseren får lov til å
gjette. TOML er eksplisitt: alle
verdier har en entydig type. Strenger er alltid i anførsels-tegn. Booleaner er nøyaktig true
eller false. Datetider er førsteklasses verdier med sin egen syntaks. Det er ingen
implisitt typetvang — parseren prøver ikke å være smart.
YAML lener seg den andre veien.
Det prøver å være praktisk: du trenger ikke anførsels-tegn rundt de fleste strenger, og parseren utleder typer
fra verdiens utseende. Det er den slutningen som biter folk. YAML 1.1-spesifikasjonen
(fortsatt brukt av mange verktøy) behandler yes, no, on, off,
true og false alle som booleaner. Den behandler ukoterte versjonsstrenger som
1.0 som flyt. Og så er det Norge-problemet.
YAMLs Berømte Fallgruver
Norge-problemet ble noe av et meme i DevOps-kretser. I YAML 1.1 parses landekoden
NO som boolsk false. Så en konfig som kartlegger ISO-landekoder
til innstillinger ville stille og rolig konvertere Norges oppføring til en boolsk. Den
YAML 1.2-spesifikasjonen fikset dette,
men mange mye brukte parsere — inkludert PyYAMLs standardmodus til nylig — retter seg fortsatt mot YAML 1.1.
Sjekk hvilken spesversjonen verktøyet ditt faktisk implementerer før du stoler på det.
NO,
Yes, on og off alle booleaner. Løsningen er enkel —
sett anførsels-tegn rundt strengene dine — men problemet er at det skjer stille. Konfigurasjonen din laster uten feil og du
får en boolsk der du forventet en streng.# YAML 1.1 implicit type coercion — all of these silently become booleans:
countries:
norway: NO # → false ← The Norway Problem
sweden: SE # → "SE" (fine, not in the boolean list)
enabled: yes # → true
disabled: no # → false
feature_flag: on # → true
another: off # → false
# Version strings can become numbers:
python_version: 3.10 # → float 3.1 (trailing zero dropped)
api_version: 1.0 # → float 1.0
# Safe: quote anything that could be ambiguous
python_version: "3.10"
country: "NO"
enabled: "yes"- Oktale literals. I YAML 1.1 parses
010som8(oktal), ikke10. Dette er viktig for filrettighetsverdier som0755. - Tab vs mellomrom. YAML forbyr tabulatortegn for innrykk. Lim inn kode fra en editor konfigurert til å bruke tabs og du får en kryptisk parsefeil — eller verre, stille feilplassering.
- Implicitte nulls. En nøkkel uten verdi blir
null. Lett å opprette ved et uhell når man redigerer for hånd. - Innrykksfølsomhet. Ett ekstra mellomrom og en verdi flyttes stille fra en forelder til en annen. Ingen feil, bare feil data.
TOML: Hvordan Eksplicitte Typer Faktisk Ser Ut
TOMLs typesystem er beskrevet i
TOML v1.0-spesifikasjonen. Strenger må
være i anførsels-tegn (enkelt eller dobbelt). Booleaner er true eller false og ingenting annet.
Heltall er heltall. Flyt er flyt. Og datetider — noe hverken JSON eller YAML har som en
native type — er førsteklasses verdier i TOML.
# TOML types are always unambiguous
name = "my-app" # string — must be quoted
version = "1.0.0" # string — quotes make it clear this is not a float
port = 8080 # integer
debug = false # boolean — only true/false, nothing else
threshold = 0.95 # float
# Datetime is a first-class type — no string parsing needed
created_at = 2024-01-15T09:30:00Z
build_date = 2024-03-20
# Arrays
allowed_hosts = ["localhost", "staging.example.com", "api.example.com"]
# Inline tables
[database]
host = "postgres.internal"
port = 5432
name = "payments_prod"
pool_size = 20Landekoden NO er bare en streng i TOML fordi den ikke er i anførsels-tegn, men TOML
utleder ikke typer fra strenglignende verdier — ukoterte verdier følger strenge syntaktiske regler. For å
være en streng trenger den anførsels-tegn. TOML har simpelthen ikke den implicitte tvangsmaskinen som forårsaker
YAMLs fallgruver.
Side om Side: En CI Pipeline-konfigurasjon
Her er et GitHub Actions-arbeidsflyt — dette er YAMLs hjemmebane. Formatet passer naturlig fordi GitHub Actions forventer YAML, den innrykksbaserte nestingen speiler den logiske strukturen, og kommentarer er essensielle for å forklare ikke-åpenbare trinnkonfigurasjoner.
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build --if-present
- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Her er den tilsvarende prosjektmanifesten i TOML — dette er der TOML skinner. Sammenlign en ekte Cargo.toml-struktur med hva den samme konfigurasjonen ville sett ut som i YAML:
# Cargo.toml — Rust package manifest
[package]
name = "payments-service"
version = "2.4.1"
edition = "2021"
description = "Payment processing microservice"
license = "MIT"
authors = ["Alice Chen <[email protected]>"]
[dependencies]
tokio = { version = "1.35", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-native-tls"] }
tracing = "0.1"
anyhow = "1.0"
[dev-dependencies]
tokio-test = "0.4"
wiremock = "0.6"
[profile.release]
opt-level = 3
lto = true
codegen-units = 1TOMLs Svakheter: Matrise av Tabeller
TOML er ikke uten ru kanter. Syntaksen for matriser av tabeller — [[doble hakeparenteser]]
— er en av de mer forvirrende tingene i spesifikasjonen. Det er hvordan du uttrykker hva JSON ville skrive som en
matrise av objekter, og det leses merkelig i starten.
# TOML array of tables — [[double brackets]] creates array entries
[[server]]
host = "web-01.example.com"
port = 443
region = "us-east-1"
[[server]]
host = "web-02.example.com"
port = 443
region = "us-west-2"
[[server]]
host = "web-03.example.com"
port = 443
region = "eu-west-1"
# The above is equivalent to this JSON:
# { "server": [
# { "host": "web-01.example.com", "port": 443, "region": "us-east-1" },
# { "host": "web-02.example.com", "port": 443, "region": "us-west-2" },
# { "host": "web-03.example.com", "port": 443, "region": "eu-west-1" }
# ]}I YAML leser den samme strukturen mer naturlig — bare en liste med innrykte egenskaper.
For dypt nestede data med gjentatte matriseoppføringer er YAMLs innrykksbaserte nesting genuint
mindre verbose enn TOMLs [[seksjon]]-overskrifter. TOML har heller ikke noe tilsvarende YAMLs
anker-og-alias-system, så du kan ikke definere en delt blokk én gang og referere til den andre steder. Hvis
du finner deg selv i å duplisere det samme settet med verdier i flere TOML-tabeller, er du nødt til å kopiere
dem manuelt.
Hvor Hvert Format Vinner i Praksis
YAML vinner som standard i disse økosystemene:
- GitHub Actions. Hele arbeidsflytsyntaksen er YAML. Du har ikke noe valg her, og det er greit — innrykkingen kartlegger godt til den nestede strukturen av jobber, trinn og betingelser.
- Kubernetes. Alle manifester — Deployments, Services, ConfigMaps, Ingress-regler — er YAML. Den Kubernetes-objektmodellen er dypt nestet, og YAML håndterer det elegant.
- Docker Compose. Tjenestdefinisjoner, nettverk, volumer — alt YAML. Kommentarer som forklarer hvorfor en port er eksponert eller hvorfor et spesifikt healthcheck-intervall brukes, er en del av dokumentasjonen.
- Ansible. Playbooks, roller, variabelfiler — YAML overalt. Kommentarstøtten brukes aktivt til å forklare ikke-åpenlyse oppgaveparametre.
TOML vinner når du kontrollerer formatet:
- Rust-prosjekter.
Cargo.tomler gullstandarden. Avhengighetsdeklarasjoner, feature flags, bygge-profiler — alt i TOML. De eksplicitte typene betyr at versjonsstrenger som"1.0.0"forblir strenger. - Python-prosjekter.
pyproject.tomlhar blitt standarden for Python- prosjektmetadata, byggekonfigurasjon og verktøyinnstillinger (Black, isort, mypy, pytest leser alle fra den). - Verktøykonfigurasjon der tvetydighet forårsaker feil. Hvis konfigurasjonen din inneholder versjons- strenger, landekoder eller andre verdier som ser ut som de kan være booleaner eller tall, eliminerer TOMLs eksplicitte typer en hel kategori av parsingoverraskelser.
- Flate konfigurasjoner. Når konfigurasjonen din primært er nøkkel-verdi-par på ett eller to nivåer av nesting, er TOML mer lesbar enn YAML og renere enn JSON.
Den Praktiske Beslutningsguiden
Det meste av tiden er valget truffet for deg av økosystemet. GitHub Actions er YAML. Kubernetes er YAML. Rust er TOML. Python-verktøy er TOML. Når du faktisk har et fritt valg, bruk dette som guiden din:
- Bruk YAML når verktøyet krever det — CI/CD-plattformer, Kubernetes, Helm-charts, Docker Compose, Ansible. Å kjempe mot konvensjonen koster mer enn det sparer.
- Bruk YAML når du trenger ankre og aliaser for å holde en kompleks konfigurasjon DRY — det er ingen TOML-ekvivalent.
- Bruk TOML for prosjektmanifester og verktøykonfigurasjon du kontrollerer — pakke-metadata, linter-innstillinger, byggekonfigurasjon.
- Bruk TOML når konfigurasjonen din inneholder verdier som YAML 1.1 kanskje feiltolker — versjonsstrenger, landekoder, alt som ligner en boolsk eller et tall.
- Sett anførsels-tegn rundt YAML-strengene dine når verdien kan forveksles med en boolsk,
tall eller null. Spesielt: versjonsnumre, landekoder, alt som starter med et siffer,
og verdier som
yes,no,on,off.
Arbeide med Begge Formater
Trenger du å validere eller prettyprinttte en konfigurasjonsfil du jobber med? TOML-formatering-verktøyet håndterer TOML-filer, og YAML-formatering-verktøyet dekker YAML. Hvis du trenger å migrere en konfigurasjon fra ett format til et annet — si, konvertere en YAML-basert verktøykonfig til TOML for et prosjekt som foretrekker det — er TOML til JSON og YAML til JSON-konverterne begge utdata JSON, som du deretter kan konvertere til målformatet ditt. Noen ganger er det å gå gjennom JSON som et mellomliggende trinn den mest pålitelige veien.
Noe verdt å vite: begge formater har sine egne JSON-kompatible undersett. Gyldig JSON er gyldig YAML (YAML er et supersett av JSON). TOML har ikke det forholdet med JSON, men TOML-spesifikasjonen er bevisst holdt enkel — det er en kort lesning, hvilket er mer enn man kan si for den fulle YAML 1.2-spesifikasjonen.
Oppsummering
TOML og YAML konkurrerer egentlig ikke. De har funnet seg til rette i forskjellige nisjer basert på sine designprioriteter. YAMLs implicitte typer og innrykksbaserte struktur gjør det til den naturlige løsningen for store, nestede konfigurasjoner vedlikeholdt av team — tenk Kubernetes-manifester og GitHub Actions- arbeidsflyter. TOMLs eksplicitte typer og flate seksjonsstruktur gjør det til den naturlige løsningen for prosjekt- manifester og verktøykonfigurasjon der en feilest versionsstreng eller landekode ville forårsake en reell feil.
Det ene å ta med seg: hvis du skriver YAML og har verdier som
ser ut som de kan være booleaner, tall eller nulls — sett anførsels-tegn rundt dem. Det er den ene vanen som
forhindrer de fleste YAML-relaterte konfigurasjonsfeil. Og hvis du starter et nytt prosjekt og kan velge
konfigurasjonsformatet ditt fritt, er TOML verdt en titt. Det
TOML GitHub-repositoriet
har gode eksempler, og når du har skrevet en Cargo.toml eller pyproject.toml,
blir formatets appell ganske tydelig.