Om du har öppnat ett Rust-projekt har du träffat TOML. Om du har rört ett Python-paket som använder
pyproject.toml har du också använt det. TOML — Tom's Obvious Minimal Language —
är konfigurationsfilformatet som tyst vinner över utvecklare som är trötta på YAMLs blankstegsfällor och
JSONs vägran att tillåta kommentarer. Skapat av Tom Preston-Werner, medgrundare av GitHub, designades TOML
kring en idé: ett konfigurationsformat ska vara så uppenbart att du kan läsa det utan en specifikation.
Låt oss se om det lever upp till det löftet.
Vad exakt är TOML?
TOML är ett konfigurationsfilformat med tre explicita designmål, angivna direkt i toppen av den officiella specifikationen: det ska vara uppenbart att läsa, minimalt i komplexitet och mappa otvetydigt till en hashtabell (en ordbok/karta i de flesta språk). Det tredje målet är det viktigaste — varje giltig TOML-fil har exakt ett korrekt parsningsresultat. Ingen förvånande typkoercering, inga booleanska YAML-fällor, ingen tvetydighet om huruvida ett värde är en sträng eller ett tal.
Formatet lånar sektionsrubrikstilen från gamla INI-filer men lägger till rätta typer, arrayer och kapslade tabeller ovanpå. Resultatet är något som känns bekant för alla som har redigerat en konfigurationsfil, men med tillräcklig struktur för att en parser kan ge dig en riktig typad datamodell ur det. Version 1.0.0 av specifikationen släpptes i januari 2021 efter år av förfining — du kan bläddra i hela TOML-specifikationen på GitHub om du vill gräva i kantfall.
Grunderna: nyckel-värde-par och kommentarer
En TOML-fil består av nyckel-värde-par. Nycklar och värden separeras av =,
och kommentarer börjar med #. Enkelt.
# 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 = falseInga citationstecken krävs på de flesta nycklar. Värden är typade — 8 är ett heltal, 0.85
är ett flyttal, false är ett booleskt värde. Inget gissande, ingen implicit koercering baserat
på hur värdet ser ut. Det här är den vardagliga TOML som du skriver 90% av tiden.
Strängtyper: grundläggande, literala och flerlinjiga
TOML har fyra strängtyper. Det täcker varje verkligt fall rent:
# 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/
'''Den literala strängtypen ('enkla citationstecken') är den som folk glömmer existerar, och den är
genuint användbar — regex-mönster och Windows-sökvägar är mycket renare utan att fördubbla bakstreck.
Välj vilken citationstil som innebär att du skriver färre bakstreck.
Tal, booleaner och datum/tider
TOMLs nativa typer täcker allt du faktiskt skulle lägga i en konfigurationsfil. Noterbart har det förstklassigt stöd för datum/tider — något YAML tekniskt sett har men hanterar inkonsekvent mellan parsers.
# 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)true och false —
inte True, TRUE, yes, on eller något av de andra varianterna
YAML 1.1 accepterar. Det är avsiktligt. Om du behöver strängen "true", citera den.Tabeller: INI-stilade sektionsrubriker
Tabeller i TOML definieras med [rubrik]-syntax. Allt under en rubrik tillhör
den tabellen tills nästa rubrik visas. Det här är funktionen som gör TOML bekant — det är
i princip INI-filer men med typer.
[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"Prickade rubriker som [database.credentials] skapar kapslade tabeller. Det parsade resultatet
är exakt vad du förväntar dig: ett database-objekt med ett kapslat credentials-objekt.
Du kan också skriva inline-tabeller för enkla fall — mer om det nedan.
Arrayer och arraytabeller
Arrayer i TOML använder hakparenteser och kan sträcka sig över flera rader. Den verkligt distinkta
TOML-funktionen är Array of Tables — definierad med dubbla parenteser [[rubrik]].
Det här är TOMLs svar på "hur uttrycker jag en lista av objekt?" utan att det ser ut som JSON.
# 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]]-syntaxen parsas till en array av tre objekt — ekvivalent med
"servers": [{...}, {...}, {...}] i JSON. Den är mer utförlig jämfört med JSON-arrayer av objekt,
men fördelen är läsbarhet när varje element har många fält. Du kan se det här mönstret flitigt i
Cargo.toml-manifest
för att definiera flera binära mål, exempel och benchmarks.
Inline-tabeller: kompakta enradsversioner
När en tabell har bara ett par fält och du inte vill ha en hel sektionsrubrik för den, låter inline-tabeller dig skriva det på en enda rad:
[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åste stanna på en enda rad och kan inte utökas senare med en [rubrik].
Använd dem för små, sammanhängande värdegrupper — de är utmärkta för saker som koordinatpar, byggmål
eller enkla flaggkonfigurationer. Använd dem inte när du har mer än tre eller fyra fält; i det läget läser
en vanlig tabell bättre.
TOML i verkligheten
TOML har snidats ut en stark nisch i Rust- och Python-ekosystemen och vinner mark på annat håll. Här är var du stöter på det dagligen:
- Rust — Cargo.toml: Varje Rust-projekt har en. Definierar paketmetadata, beroenden, funktioner och byggmål. Cargo-manifestreferensen är den mest detaljerade verkliga TOML-guiden du hittar.
- Python — pyproject.toml: PEP 518 och PEP 621 standardiserade TOML som Python-projektmetadataformatet. Poetry, Hatch, PDM och setuptools läser alla från det.
- Deno: Denos konfigurationsfil stöder TOML utöver JSON.
- Hugo: Den statiska webbplatsgeneratorn Hugo accepterar TOML som konfiguration och front-matter-format — du ser det mellan
+++-avgränsare i toppen av Markdown-filer. - uv: Den snabba Python-pakethanteraren från Astral använder pyproject.toml för all konfiguration, vilket gör TOML till de facto-standard för nya Python-verktyg.
Om du behöver konvertera en befintlig konfiguration mellan format hanterar TOML till JSON och JSON till TOML konverterarna den strukturella mappningen åt dig. Eller använd TOML Formatter för att städa upp inkonsekvent avstånd i en befintlig fil och TOML Validator för att fånga syntaxfel innan de dyker upp i produktion.
Parsning av TOML i Python
Sedan Python 3.11 inkluderar standardbiblioteket
tomllib
— inget externt beroende behövs. För Python 3.9 och 3.10 har backporten
tomli
ett identiskt API, så du kan växla mellan dem med ett enda importalias.
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")Observera att tomllib.load() kräver binärt läge ("rb"). Det är avsiktligt —
TOML kräver UTF-8-kodning, och att öppna i binärt läge låter parsern hantera kodningskontroller själv.
Det är en liten fallgrop som fångar folk första gången.
Parsning av TOML i Rust
I Rust är craten toml
standardvalet. Den integreras tätt med serde, så du kan deserialisera direkt till
dina egna structs med minimal standardkod:
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(())
}Lägg till toml = "0.8" och serde = { version = "1", features = ["derive"] }
till din [dependencies] i Cargo.toml så är du igång. Serde derive-makrona hanterar all
fältmappning. Om dina struct-fältnamn använder snake_case men TOML-nycklarna använder kebab-case, lägg till
#[serde(rename_all = "kebab-case")] på struct-nivå och allt mappar automatiskt.
TOML vs YAML vs JSON — när man ska välja vilket
Den här frågan dyker upp i varje nytt projekt. Här är den ärliga uppdelningen:
- TOML: Bäst för konfigurationsfiler som människor skriver och underhåller, där typade värden spelar roll och nesting är grund till måttlig. Styrka: appkonfigurationer, byggmanifest, verktygsinställningar. Brister vid djup nesting — 4+ nivåer blir besvärligt med upprepade sektionsrubriker.
- YAML: Bäst när du skriver strukturerad data med massor av listor av objekt (Kubernetes-manifest, GitHub Actions-arbetsflöden). Flerlinjigt strängstöd är genuint bättre än TOMLs. Nackdelen: blankstegskänslighet och YAML 1.1-typkoercering skapar verkliga buggar i praktiken.
- JSON: Bäst för maskin-till-maskin-datautbyte, API:er och när du behöver bredast möjliga verktygsstöd. Inte bra för mänskligt underhållen konfiguration — inga kommentarer och strängescaping är omständlig.
En riktig pyproject.toml
För att sätta ihop allt, här är en realistisk pyproject.toml för ett Python-bibliotek —
den typ du hittar i ett modernt öppen källkod-projekt. Notera hur formatet bär en hel del strukturerad
information medan det fortfarande är lätt att skanna:
[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 = 90Det här är riktig TOML som gör riktigt arbete. Varje [tool.x]-sektion är ett separat namnrymden
för ett annat verktyg — ruff, mypy, coverage — alla lever i en fil utan att trampa på varandra.
Ingen djup nesting behövs, allt är läsbart på ett ögonkast.
Sammanfattning
TOML levererar på sitt löfte: läsbart, otvetydigt och rent typad. Om du startar ett nytt projekt i Rust, Python eller Go är TOML värt att välja som standard för konfigurationsfiler — särskilt filer som committas till källkontroll och redigeras av flera personer. Bristen på blankstegskänslighet ensam är en lättnad jämfört med YAML. För att arbeta med TOML-filer direkt i din webbläsare hanterar TOML Formatter och TOML Validator de vanligaste uppgifterna. Och om du migrerar ett befintligt projekt från JSON eller behöver brygga TOML till en JSON-baserad pipeline har konverterarna TOML till JSON och JSON till TOML dig täckt.