TOML vs YAML vs JSON: picking a config format in 2026
Rust picked TOML. Python packaging picked TOML. Cloudflare Workers picked TOML. Here's why the config landscape shifted, and how to move between TOML, YAML, and JSON without breakage.
Why TOML is quietly winning
Five years ago, YAML was the default config format for anything longer than .env. In 2026 the picture has shifted: TOML runs Rust (Cargo.toml), Python packaging (pyproject.toml), Cloudflare Workers (wrangler.toml), the Zig build system, Poetry, and countless CLIs.
The pitch: TOML is what YAML was supposed to be โ human-friendly, unambiguous, easy to write. Without YAML's traps (the Norway problem, indent-sensitivity, silent type coercion, six versions of multi-line strings).
The three-format decision matrix
| Feature | JSON | YAML | TOML |
|---|---|---|---|
| Comments | โ | โ | โ |
| Trailing commas | โ | n/a | โ (in arrays) |
| Multi-line strings | โ (escape \n) | โ (three styles) | โ (""") |
| Indent-sensitive | โ | โ | โ |
| Boolean coercion pitfalls | โ | โ (yes/no/on/off) | โ |
| Anchors / references | โ | โ | โ |
| Nested structures | Free-form | Free-form | Table-based |
| Machine-only interchange | โโ | โ | โ |
| Human-authored config | โ | โ | โโ |
JSON wins when machines write and machines read (APIs, RPC). YAML wins when you need anchors/refs (Kubernetes, some CI systems). TOML wins for human-authored config โ the tables model matches how people mentally group settings.
The TOML mental model
Everything is a table (equivalent to a JSON object). The root is a table. [section] opens a new table. [[section]] starts an array-of-tables. That's the whole structure.
# Root-level values
name = "712tools"
version = "1.0"
# A named table
[owner]
name = "Ada"
email = "ada@example.com"
# An array-of-tables (like a JSON array of objects)
[[servers]]
host = "us-east.example.com"
region = "us-east-1"
[[servers]]
host = "eu-west.example.com"
region = "eu-west-1"
Every key has one type. Strings are quoted; numbers, booleans, and dates are bare. Arrays use []. Inline tables use {} for compact one-liners.
That's the full spec worth memorizing. No indent traps, no anchor magic.
When TOML gets ugly
Deeply nested structures. TOML tables model 1-2 levels of nesting cleanly; 4+ levels start to feel awkward because you keep repeating the full dotted path:
[services.web.upstreams.primary]
host = "web-primary"
For anything heavily nested (Kubernetes manifests, complex CI pipelines), YAML or JSON reads better. Cargo.toml and pyproject.toml stay flat enough for TOML to shine.
The migration workflows
Migrating from JSON to TOML (e.g., converting an old config.json to a config.toml):
Convert with TOML โ JSON Converter. Every top-level object becomes a table, every nested object becomes a sub-table, every array-of-objects becomes an array-of-tables ([[...]]).
Migrating from YAML to TOML (rare but happens โ e.g., a new Rust rewrite of a Python service):
Two-step: YAML โ JSON with YAML โ JSON Converter, then JSON โ TOML. The intermediate JSON step drops YAML-specific features (anchors, complex multi-line strings) that don't have TOML equivalents.
Migrating from .env to TOML for structured secrets and config:
Two-step: .env โ JSON with .env โ JSON Converter, then JSON โ TOML. Group related keys into tables ([database], [redis]) for cleaner organization than the flat .env layout.
Cargo.toml, pyproject.toml, wrangler.toml โ the three you'll edit most
Cargo.toml (Rust):
[package]
name = "my-crate"
version = "0.1.0"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
pyproject.toml (Python packaging, PEP 518+):
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-package"
version = "0.1.0"
dependencies = [
"requests>=2.28",
"pydantic>=2.0",
]
wrangler.toml (Cloudflare Workers):
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2026-08-17"
[[kv_namespaces]]
binding = "CACHE"
id = "abc123"
All three use the same core syntax. Learn TOML once, edit all three fluently.
Common TOML mistakes
1. Extra quotes on numbers. port = "3000" parses as a string. TOML has actual number types โ port = 3000.
2. Missing quotes on strings. name = 712tools parses as an identifier in some parsers and fails in others. Quote it: name = "712tools".
3. Confusing [table] with [[array-of-tables]]. Single brackets = one table. Double brackets = one entry in an array of tables. Getting this wrong changes the parsed structure entirely.
4. Deep nesting via dotted keys. a.b.c = 1 is legal but hard to read. Prefer a table:
[a.b]
c = 1
5. Multi-line strings preserving indentation. Basic multi-line strings (""") preserve every space including leading indent. Use trimming ("""\) or the literal form (''') as appropriate.
Related workflows
- YAML โ JSON Converter โ for Kubernetes, GitLab CI, docker-compose.
- .env โ JSON Converter โ for the flat-config end of the spectrum.
- JSON Formatter โ for eyeballing the converted output at any step.
Tools mentioned in this post
Related reading
.env files in 2026: parsing, secrets management, and portability
Every framework reads .env slightly differently. Here's the shared subset that works everywhere, the security pitfalls, and how to sync .env with JSON, YAML, and cloud secret stores.
YAML pitfalls: the Norway problem, indentation, and anchors
YAML looks like the friendly config format until it silently converts 'NO' to false. Here are the traps in YAML 1.1, why 1.2 fixes some of them, and when to switch to JSON.
JSON to TypeScript: workflows that scale beyond a single sample
A one-shot JSON โ interface tool is great for demos and dead for production. Here are the patterns real teams use to keep types in sync with real APIs.
Why your JSON won't parse (and how to fix it in 30 seconds)
Trailing commas, unquoted keys, single quotes, comments โ the five errors that break 90% of hand-written JSON, and how to catch them without a build step.
Shan builds 712 Tools. He holds a Master's degree in Mechanical Engineering and now works as a Software Engineer, shipping browser-based developer utilities out of Ontario, Canada. Learn more ยท 712studiogames@gmail.com