JSON vs YAML vs TOML — Which Config Format?
Photo by Unsplash on Unsplash
Table of Contents
The Cheat-Sheet Answer
I've shipped bugs in all three, but only YAML has cost me a genuinely baffling hour — more on that below. Picking a format isn't about which is "best" in the abstract; it's about who's editing the file and what reads it. Let me walk through each, with the gotchas I actually hit.
JSON: The Universal Default
The trouble starts when a human has to edit it. JSON is strict on purpose: every key needs double quotes, you can't leave a trailing comma after the last item, and there are no comments — none, by design. That last one bites hardest for config. When you can't write `// this timeout is in seconds` next to a value, you lose the context that makes a config file maintainable. People resort to fake `"_comment"` keys, which is a smell.
JSON's other quirk is that it's verbose for deeply nested config and unforgiving about small mistakes. One missing brace and the whole file fails to parse, often with an error pointing at the wrong line. This is exactly the kind of thing a validator saves you from — when a file won't parse, I paste it into the ToolsFuel JSON formatter to find the offending comma or brace instantly instead of squinting at it.
Where JSON genuinely shines: anything a program generates or consumes. Build output, API payloads, data you're shipping between services. If a human rarely opens the file by hand, JSON's strictness is a feature, not a burden. And if you're wrangling JSON in code, the JSON.stringify vs JSON.parse distinction is worth having down cold, since that's how you move between JSON text and live objects.
A quick word on the variants people reach for to paper over JSON's gaps. JSONC ("JSON with comments") is what VS Code uses for its settings file — it's plain JSON plus `//` comments, and it's non-standard, so don't feed it to a strict parser. JSON5 goes further, allowing trailing commas, unquoted keys, and single quotes, which makes it far friendlier to hand-edit. Both exist precisely because standard JSON is painful to write by hand, and both are a signal that if you're editing a lot of config manually, you probably want a different format underneath. That's the thread running through this whole comparison: JSON is a superb *data* format that got pressed into service as a *config* format, and the friction you feel editing it is the mismatch showing. When the file is data, none of this bites; when it's config a person maintains, it does. Once you've untangled a nested payload, exporting it elsewhere is easy too — I lean on the JSON to CSV converter when I need a JSON array in a spreadsheet.
YAML: Readable Until It Isn't
Photo by Unsplash on Unsplash
And then it bites you. YAML is indentation-sensitive like Python, so a single stray space can silently change the structure — nesting a key one level deeper than you meant, with no error, just wrong behavior. Mixing tabs and spaces breaks it outright. On a big file, tracking down a misaligned block is genuinely miserable.
The deeper trap is YAML's eagerness to guess types. This is the famous "Norway problem": write `country: NO` and older YAML parsers read `NO` as the boolean `false`, not the string "NO". The same happens with `yes`, `on`, `off`, and a dozen other words that silently become booleans. Version numbers like `1.20` can lose their trailing zero and become the number `1.2`. My baffling hour came from a value that looked like a string to me and parsed as something else to the machine — the fix was wrapping it in quotes, which YAML supports but doesn't require, so nobody had bothered.
YAML earns its place when a tool mandates it (you don't get to argue with Kubernetes) or when a config is long and deeply nested and readability truly wins. Just quote anything that could be misread, keep your indentation consistent, and run it through a linter. Treat YAML's flexibility as something to constrain, not to enjoy.
TOML: The Config-File Sweet Spot
What makes TOML pleasant is that it fixes YAML's worst habits without giving up readability. It has comments (`#`), same as YAML. But every value has exactly one obvious type — a quoted string is always a string, so there's no Norway problem, no `1.20` quietly becoming `1.2`. And it doesn't rely on significant whitespace, so a stray space won't reshape your file. You get the readability win with far fewer landmines.
The trade-off is that TOML gets awkward for deeply nested or highly dynamic structures. Its `[table]` and `[[array-of-tables]]` syntax is clean for flat-ish config but clumsy once you're four levels deep — that's where YAML's indentation or JSON's braces actually read better. TOML is at its best for the kind of config a human hand-edits: build settings, dependency lists, tool configuration.
So where does that leave you? Here's how I decide:
- Machines exchanging data, or an API? JSON. It's the lingua franca and nothing beats its support. - A tool that demands YAML (Kubernetes, CI pipelines), or big nested config where readability rules? YAML — just quote your ambiguous values. - Config a person edits by hand — build tools, dependencies, app settings? TOML, for the comments and the lack of surprises.
None of them is universally right, and most real projects end up with all three: JSON for data, YAML for the CI file, TOML for the package manifest. Knowing why each exists is what lets you stop fighting the format and pick the one that fits the job. For the rest of the formatters and converters I keep open while wrangling config, the ToolsFuel tools directory has them in one place.
Frequently Asked Questions
Why doesn't JSON support comments?
Its creator, Douglas Crockford, left comments out on purpose so that people wouldn't stuff parsing directives into them and break interoperability. The result is a clean interchange format but a frustrating config format, since you can't explain a value inline. Teams work around it with a separate docs file or fake comment keys, but if comments matter to you, TOML or YAML is the better pick. When JSON won't parse, the [ToolsFuel JSON formatter](/tools/json-formatter) points you straight at the syntax error.
Is YAML a superset of JSON?
Yes, modern YAML is a superset, which means valid JSON is also valid YAML and most YAML parsers will happily read a JSON file. That's handy for migration, since you can rename a file and start adding comments and cleaner syntax gradually. The reverse isn't true, though — YAML's indentation style and anchors have no JSON equivalent, so you can't feed arbitrary YAML to a JSON parser.
What is the Norway problem in YAML?
It's the classic bug where YAML reads the country code NO as the boolean false instead of the string "NO", because older parsers treat no, yes, on, and off as booleans. The same type-guessing can turn a version like 1.20 into the number 1.2. The fix is simple but easy to forget: wrap anything ambiguous in quotes so it's forced to stay a string.
Why do Rust and Python use TOML?
Both wanted a config format that humans edit comfortably but that has no ambiguity — Cargo.toml for Rust dependencies and pyproject.toml for Python packaging. TOML gives them comments, one clear type per value, and no whitespace traps, which suits a manifest people open by hand every day. It reads like INI but has a real spec, so tools can parse it reliably across languages.
Which format is fastest to parse?
JSON, by a wide margin, because its grammar is small and parsers are heavily optimized in every language. YAML is the slowest of the three since its spec is large and full of edge cases the parser has to handle. TOML sits in the middle. For anything performance-sensitive or machine-to-machine, that speed is one more reason JSON stays the default for data interchange.
Try ToolsFuel
23+ free online tools for developers, designers, and everyone. No signup required.
Browse All Tools