Hvis du har åpnet et Rust-prosjekt, har du møtt TOML. Hvis du har vært borti en Python-pakke som bruker pyproject.toml, har du brukt det også. TOML — Tom's Obvious Minimal Language — er konfigurasjonsfil-formatet som stille og rolig vinner over utviklere som er lei av YAMLs mellomrom- fallgruver og JSONs avvisning av kommentarer. Skapt av Tom Preston-Werner, medgrunnlegger av GitHub, ble TOML designet rundt én idé: et konfigurasjonsformat bør være så åpenbart at du kan lese det uten en spesifikasjon. La oss se om det innfrir det løftet.

Hva Nøyaktig Er TOML?

TOML er et konfigurasjonsfil-format med tre eksplisitte designmål, stavet ut rett øverst i den offisielle spesifikasjonen: det skal være åpenbart å lese, minimalt i kompleksitet og kartlegge entydig til en hashtabell (en ordbok/kart i de fleste språk). Det tredje målet er det viktigste — alle gyldige TOML-filer har nøyaktig ett korrekt parseresultat. Ingen overraskende typetvang, ingen YAML-lignende boolske landminer, ingen tvetydighet om hvorvidt en verdi er en streng eller et tall.

Formatet låner seksjonsoverskrift-stilen fra gamle INI-filer men legger til riktige typer, matriser og nestede tabeller på toppen. Resultatet er noe som føles kjent for alle som har redigert en konfigurasjonsfil før, men med nok struktur til at en parser kan gi deg en ekte typet datamodell ut av det. Versjon 1.0.0 av spesifikasjonen ble utgitt i januar 2021 etter års raffinement — du kan bla gjennom hele TOML-spesifikasjonen på GitHub hvis du vil grave inn i grensetilfellene.

Grunnleggende: Nøkkel-verdi-par og Kommentarer

En TOML-fil er bygget opp av nøkkel-verdi-par. Nøkler og verdier er atskilt med =, og kommentarer starter med #. Enkelt.

toml
# Cargo.toml — Rust package manifest
[package]
name = "image-resizer"
version = "0.4.2"
edition = "2021"
authors = ["Ada Lovelace <[email protected]>"]
description = "Fast image resizing with Lanczos3 resampling"
license = "MIT"
repository = "https://github.com/example/image-resizer"

# Integers, floats, booleans — all native types
max_threads = 8
quality_default = 0.85
verbose_logging = false

Ingen anførsels-tegn nødvendig på de fleste nøkler. Verdier er typede — 8 er et heltall, 0.85 er en flyt, false er en boolsk. Ingen gjetning, ingen implisitt tvang basert på hvordan verdien ser ut. Dette er det hverdagslige TOML du vil skrive 90 % av tiden.

Strengtyper: Grunnleggende, Literal og Flerlinjete

TOML har fire strengtyper. Dette dekker alle virkelige tilfeller rent:

toml
# Basic strings — double quotes, support escape sequences
greeting = "Hello, \nworld!"
path = "C:\\Users\\ada\\Documents"

# Literal strings — single quotes, no escape processing at all
regex_pattern = '\d{4}-\d{2}-\d{2}'
windows_path = 'C:\Users\ada'

# Multiline basic string — triple double quotes
sql_query = """
  SELECT user_id, email, created_at
  FROM users
  WHERE active = true
    AND created_at > '2024-01-01'
  ORDER BY created_at DESC
"""

# Multiline literal string — triple single quotes, no escapes
shell_script = '''
#!/bin/bash
echo "Deploying $APP_NAME to $ENV"
kubectl apply -f k8s/
'''

Literal-strengtypen ('enkle anførsels-tegn') er den folk glemmer eksisterer, og den er genuint nyttig — regex-mønstre og Windows-baner er mye renere uten escape-dobling. Velg den anførsels-tegn-stilen som betyr at du skriver færre backslash-er.

Tall, Booleaner og Datetider

TOMLs native typer dekker alt du faktisk ville legge inn i en konfigurasjonsfil. Spesielt har det førsteklasses datetime-støtte — noe YAML teknisk har men håndterer inkonsekvent på tvers av parsere.

toml
# Integers — underscores allowed as separators (like numeric literals in code)
max_connections = 1_000_000
port = 5432
hex_color = 0xFF6B6B      # hex prefix supported
octal_permissions = 0o755  # octal prefix supported

# Floats
pi = 3.14159265
compression_ratio = 1.5e-3
infinity_val = inf         # special values: inf, -inf, nan

# Booleans — lowercase only (not True, TRUE, yes, on)
ssl_enabled = true
dry_run = false

# Datetimes — RFC 3339 format
created_at = 2024-03-15T09:30:00Z
updated_at = 2024-03-15T14:22:10+05:30
log_date = 2024-03-15           # local date (no time)
backup_time = 03:00:00          # local time (no date)
TOML-booleaner er strengt med små bokstaver. Kun true og false — ikke True, TRUE, yes, on, eller noen av de andre variantene YAML 1.1 godtar. Dette er tilsiktet. Hvis du trenger strengen "true", sett den i anførsels-tegn.

Tabeller: INI-Lignende Seksjonsoverskrifter

Tabeller i TOML er definert med [overskrift]-syntaks. Alt under en overskrift tilhører den tabellen inntil neste overskrift vises. Dette er funksjonen som gjør TOML kjent — det er i bunn og grunn INI-filer men med typer.

toml
[database]
host = "db.internal"
port = 5432
name = "app_production"
pool_size = 20

[database.credentials]
username = "app_user"
# Don't put real passwords here — use env vars or a secrets manager
password_env = "DB_PASSWORD"

[server]
host = "0.0.0.0"
port = 8080
workers = 4

[server.tls]
enabled = true
cert_file = "/etc/ssl/certs/app.crt"
key_file = "/etc/ssl/private/app.key"

Prikk-overskrifter som [database.credentials] lager nestede tabeller. Det analyserte resultatet er akkurat hva du ville forvente: et database-objekt med et nestet credentials-objekt. Du kan også skrive inline-tabeller for enkle tilfeller — mer om det nedenfor.

Matriser og Matrise av Tabeller

Matriser i TOML bruker hakeparenteser og kan spenne over flere linjer. Den virkelig særegne TOML-funksjonen er Matrise av Tabeller — definert med doble hakeparenteser [[overskrift]]. Dette er TOMLs svar på "hvordan uttrykker jeg en liste med objekter?" uten at det ser ut som JSON.

toml
# Regular arrays — can be split across lines, trailing comma is fine
allowed_origins = [
  "https://app.example.com",
  "https://admin.example.com",
  "http://localhost:3000",
]

supported_formats = ["jpeg", "png", "webp", "avif"]
retry_delays_ms = [100, 250, 500, 1000, 2000]

# Array of Tables — [[double brackets]]
# Each [[servers]] header appends a new object to the servers array
[[servers]]
name = "web-01"
ip = "10.0.1.10"
role = "primary"
tags = ["web", "prod"]

[[servers]]
name = "web-02"
ip = "10.0.1.11"
role = "replica"
tags = ["web", "prod"]

[[servers]]
name = "db-01"
ip = "10.0.2.10"
role = "primary"
tags = ["database", "prod"]

Den [[servers]]-syntaksen parses til en matrise av tre objekter — tilsvarende "servers": [{...}, {...}, {...}] i JSON. Det er verbose sammenlignet med JSON-matriser av objekter, men fordelen er lesbarhet når hvert element har mange felt. Du kan se dette mønsteret mye i Cargo.toml-manifester for å definere flere binære mål, eksempler og bench-oppføringer.

Inline-tabeller: Kompakte Énlinjere

Når en tabell bare har et par felt og du ikke vil ha en hel seksjonsoverskrift for det, lar inline-tabeller deg skrive det på én linje:

toml
[build]
# Inline table — must stay on one line
target = { arch = "x86_64", os = "linux", libc = "musl" }

# Equivalent to writing:
# [build.target]
# arch = "x86_64"
# os = "linux"
# libc = "musl"

[feature_flags]
auth   = { enabled = true, rollout_pct = 100 }
search = { enabled = true, rollout_pct = 50 }
beta   = { enabled = false, rollout_pct = 0 }

Inline-tabeller må bli på én linje og kan ikke utvides senere med en [overskrift]. Bruk dem for små, sammenhengende verdigrupper — de er flotte for ting som koordinatpar, byggemål eller enkle flaggkonfigurasjoner. Ikke bruk dem når du har mer enn tre eller fire felt; på det punktet leser en vanlig tabell bedre.

TOML i den Virkelige Verden

TOML har skåret ut en sterk nisje i Rust- og Python-økosystemene, og vinner terreng andre steder. Her er hvor du vil møte det daglig:

  • Rust — Cargo.toml: Hvert Rust-prosjekt har en. Definerer pakke-metadata, avhengigheter, funksjoner og byggemål. Cargo-manifestreferansen er den mest detaljerte virkelige TOML-bruksguiden du finner.
  • Python — pyproject.toml: PEP 518 og PEP 621 standardiserte TOML som Python-prosjektmetadata-formatet. Poetry, Hatch, PDM og setuptools leser alle fra det.
  • Deno: Deno-konfigurasjonsfilen støtter TOML i tillegg til JSON.
  • Hugo: Hugo statisk nettstedsgenerator godtar TOML som konfig- og frontmatter-format — du ser det mellom +++-avgrensere øverst i Markdown-filer.
  • uv: Den raske Python-pakkebehandleren fra Astral bruker pyproject.toml for all konfigurasjon, noe som gjør TOML til de facto standard for nytt Python-verktøy.

Hvis du trenger å konvertere en eksisterende konfig mellom formater, håndterer TOML til JSON og JSON til TOML- konverterne den strukturelle kartleggingen for deg. Eller bruk TOML-formatering-verktøyet til å rydde opp inkonsekvent mellomrom i en eksisterende fil, og TOML-validator-verktøyet til å fange syntaksfeil før de dukker opp i produksjon.

Parse TOML i Python

Siden Python 3.11 inkluderer standardbiblioteket tomllib — ingen ekstern avhengighet nødvendig. For Python 3.9 og 3.10 har tomli-tilbakeporten et identisk API, slik at du kan bytte mellom dem med ett enkelt importaliasert.

python
import sys

if sys.version_info >= (3, 11):
    import tomllib
else:
    import tomli as tomllib  # pip install tomli

# tomllib only reads binary mode — open with "rb"
with open("pyproject.toml", "rb") as f:
    config = tomllib.load(f)

# Types match TOML exactly: str, int, float, bool, datetime, list, dict
project_name = config["project"]["name"]               # str
python_requires = config["project"]["requires-python"] # str
dependencies = config["project"]["dependencies"]        # list[str]

print(f"Project: {project_name}")
print(f"Requires Python: {python_requires}")
print(f"Dependencies ({len(dependencies)}):")
for dep in dependencies:
    print(f"  {dep}")

# Parse from a string with tomllib.loads()
raw = """
[server]
host = "localhost"
port = 8080
debug = true
"""
server_config = tomllib.loads(raw)
print(server_config["server"]["port"])   # 8080 (int, not "8080")

Merk at tomllib.load() krever binærmodus ("rb"). Dette er tilsiktet — TOML krever UTF-8-koding, og å åpne i binærmodus lar parseren håndtere kodingskontrollen selv. Det er en liten fallgruve som tar folk første gang.

Parse TOML i Rust

I Rust er toml-crate standardvalget. Den integrerer tett med serde, slik at du kan deserialisere direkte til dine egne structs med minimal kode:

rust
use serde::Deserialize;
use std::fs;

#[derive(Debug, Deserialize)]
struct AppConfig {
    server: ServerConfig,
    database: DatabaseConfig,
    feature_flags: FeatureFlags,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    host: String,
    port: u16,
    workers: usize,
}

#[derive(Debug, Deserialize)]
struct DatabaseConfig {
    host: String,
    port: u16,
    name: String,
    pool_size: u32,
}

#[derive(Debug, Deserialize)]
struct FeatureFlags {
    enable_beta: bool,
    max_upload_mb: u32,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let raw = fs::read_to_string("config.toml")?;
    let config: AppConfig = toml::from_str(&raw)?;

    println!("Server: {}:{}", config.server.host, config.server.port);
    println!("DB pool size: {}", config.database.pool_size);
    println!("Beta enabled: {}", config.feature_flags.enable_beta);

    Ok(())
}

Legg til toml = "0.8" og serde = { version = "1", features = ["derive"] } i [dependencies] i Cargo.toml og du er klar. Serde derive-makroene håndterer all feltmapping. Hvis struct-feltnavnene dine bruker snake_case men TOML-nøklene bruker kebab-case, legg til #[serde(rename_all = "kebab-case")] på struct-nivå og alt mapper automatisk.

TOML vs YAML vs JSON — Når Velger Man Hva

Dette spørsmålet dukker opp på hvert nytt prosjekt. Her er den ærlige gjennomgangen:

  • TOML: Best for konfigurasjonsfiler som mennesker skriver og vedlikeholder, der typede verdier er viktige og nesting er grunn til moderat. Sødøme sted: appkonfigurasjoner, byggemanifester, verktøyinnstillinger. Bryter sammen ved dyp nesting — 4+ nivåer blir vanskelig med gjentatte seksjonsoverskrifter.
  • YAML: Best når du skriver strukturerte data med mange lister-av-objekter (Kubernetes-manifester, GitHub Actions-arbeidsflyter). Flerlinjet strengstøtte er genuint bedre enn TOMLs. Ulempen: mellomrom-sensitivitet og YAML 1.1-typetvang skaper reelle feil i praksis.
  • JSON: Best for maskin-til-maskin datautveksling, API-er og når du trenger bredest mulig verktøykjedesupport. Ikke flott for menneskelig vedlikeholdt konfig — ingen kommentarer, og strengescaping er kjedelig.
Rask tommelfingerregel: Hvis en utvikler redigerer filen for hånd i en teksteditor, er TOML vanligvis den mest behagelige opplevelsen. Hvis den er generert av et verktøy eller konsumert av et dusin forskjellige systemer på forskjellige språk, vinner JSONs universalitet. YAML lever i midten — flott for DevOps-konfig som mennesker skriver men verktøy behandler tungt.

En Ekte pyproject.toml

For å sette alt sammen, her er en realistisk pyproject.toml for et Python-bibliotek — den typen du ville finne på et moderne åpen kildekode-prosjekt. Legg merke til hvordan formatet bærer mye strukturert informasjon mens det fortsatt er lett å skumme:

toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "httpx-cache"
version = "1.2.0"
description = "Transparent HTTP caching layer for httpx"
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.9"
authors = [
  { name = "Ada Lovelace", email = "[email protected]" },
]
keywords = ["http", "cache", "httpx", "async"]
classifiers = [
  "Development Status :: 4 - Beta",
  "Intended Audience :: Developers",
  "License :: OSI Approved :: MIT License",
  "Programming Language :: Python :: 3.9",
  "Programming Language :: Python :: 3.10",
  "Programming Language :: Python :: 3.11",
  "Programming Language :: Python :: 3.12",
]
dependencies = [
  "httpx>=0.25.0",
  "anyio>=4.0.0",
]

[project.optional-dependencies]
redis = ["redis>=5.0.0"]
dev = [
  "pytest>=7.4.0",
  "pytest-asyncio>=0.23.0",
  "coverage[toml]>=7.3.0",
  "ruff>=0.1.0",
  "mypy>=1.7.0",
]

[project.urls]
Homepage = "https://github.com/example/httpx-cache"
Changelog = "https://github.com/example/httpx-cache/blob/main/CHANGELOG.md"

[tool.ruff]
line-length = 100
target-version = "py39"

[tool.ruff.lint]
select = ["E", "F", "I", "UP"]

[tool.mypy]
strict = true
python_version = "3.9"

[tool.coverage.run]
source = ["httpx_cache"]
branch = true

[tool.coverage.report]
fail_under = 90

Dette er ekte TOML som gjør ekte arbeid. Hver [tool.x]-seksjon er et separat navnerom for et annet verktøy — ruff, mypy, coverage — alle lever i én fil uten å tråkke på hverandre. Ingen dyp nesting nødvendig, alt er lesbart med ett blikk.

Oppsummering

TOML innfrir løftet: lesbart, entydig og rent typet. Hvis du starter et nytt prosjekt i Rust, Python eller Go, er TOML verdt å bruke som standard for konfigurasjonsfiler — spesielt filer som vil bli committed til kildekontroll og redigert av flere. Mangelen på mellomromsensitivitet alene gjør det til en lettelse sammenlignet med YAML. For å jobbe med TOML-filer direkte i nettleseren din, håndterer TOML-formatering og TOML-validator-verktøyene de vanligste oppgavene. Og hvis du migrerer et eksisterende prosjekt fra JSON eller trenger å bringe TOML inn i en JSON-basert pipeline, dekker TOML til JSON og JSON til TOML-konverterne det.