JSON vs YAML vs TOML: which config format to use
The real tradeoffs between the three config formats: comments, ambiguity, nesting, tooling, and the values YAML silently changes. With a decision table.
Three formats can hold the same configuration, and every project ends up picking one, often by whichever tool got there first. The choice is worth making on purpose, because each format has one property that decides most real arguments: JSON has no comments, YAML has ambiguity, and TOML has awkward nesting. Everything else is preference.
JSON: precise, and unkind to humans
JSON's grammar is small enough to fit on a page, and every language parses it identically. That is its strength: a JSON document means exactly one thing, and the parser will tell you the line and column of anything it does not understand.
The costs are all ergonomic. No comments — a config file that cannot explain itself. No trailing commas, so reordering a list means touching two lines. Every key quoted. Nested structures are fine, but a long file is a wall of braces. For anything a human edits regularly, this is a real tax, which is why JSON5 and JSONC exist and why tools like TypeScript and VS Code quietly accept comments in files with a .json extension.
Use it when machines write and read the file, when a strict schema matters, or when the consumer is a JavaScript runtime.
YAML: readable, and occasionally wrong
YAML looks like the outline you would write on a whiteboard: indentation instead of braces, dashes for lists, comments anywhere. For files that people read and edit — Kubernetes manifests, CI pipelines, Compose files — that readability is why it won.
The cost is that YAML tries to guess what you mean, and the YAML 1.1 rules that most parsers still apply guess wrong in ways that pass validation:
22:22is a base-60 number (1342), not a port mapping.NO,off,narefalse;yes,on,yaretrue. A country code ofNObecomes a boolean.0123is octal 83;3.10is the float3.1.- A tab in the indentation is an error; one space too many is a different structure.
Every one of those has a real incident behind it. The defence is quoting anything that looks like it might be a number, a boolean or a time, and validating with a tool that understands the 1.1 rules — YAML Validator warns about each ambiguous scalar. YAML 1.2 removed most of this, but you cannot assume which version the consumer implements.
Use it when humans maintain the file and the ecosystem expects it. Quote defensively.
TOML: unambiguous, and flat by nature
TOML was designed as a reaction to both: the readability of an INI file with a real specification. Strings are always quoted, so there is no guessing about types. Comments are first-class. Dates are a native type. Rust's Cargo, Python's pyproject.toml, and a growing number of tools use it for exactly these reasons.
The cost is nesting. A deeply nested structure becomes [server.tls.client_auth] table headers and [[array.of.tables]], which reads well two levels deep and badly four levels deep. TOML is at its best for configuration that is mostly flat with a few sections — which describes most application config and does not describe a Kubernetes manifest.
Use it for application and tool configuration edited by people, when the structure is shallow.
The decision table
| JSON | YAML | TOML | |
|---|---|---|---|
| Comments | No | Yes | Yes |
| Type ambiguity | None | Significant (1.1) | None |
| Deep nesting | Fine | Fine | Awkward |
| Human editing | Tiresome | Pleasant | Pleasant when flat |
| Parser agreement | Universal | Version-dependent | Good |
| Best for | Data interchange, strict schemas | Manifests, pipelines, anything the ecosystem dictates | App and tool config |
Converting between them
Conversion is lossless in one direction and lossy in the other. JSON to YAML or TOML is safe: every JSON value has a representation. Going from YAML loses comments and anchors, and any value that YAML reinterpreted has already changed before the converter sees it — a 22:22 that became 1342 stays 1342 in the JSON.
JSON to YAML quotes the ambiguous values so the round trip survives a 1.1 parser. YAML to JSON is the quickest way to see what a YAML file actually parses to, braces and all, which is the diagnostic to run before blaming the application. TOML to JSON does the same for TOML.
A rule that resolves most arguments
If the ecosystem has already chosen — Kubernetes, GitHub Actions, Cargo, Compose — use what it chose; fighting the convention costs more than any format's flaws. If you are choosing for your own application config, pick TOML for flat files and YAML for nested ones, and reserve JSON for data rather than configuration. And whichever you pick, run it through a validator before it reaches production; the formats fail differently, but all three fail.