YAML vs JSON vs TOML: Choosing the Right Config Format
YAML, JSON, and TOML all serialize structured data into plain text, but they were designed for different jobs and carry different trade-offs. Picking the wrong one for a project leads to brittle config files, parsing surprises, and frustrated contributors. This guide compares the three on syntax, data types, comments, tooling, and the failure modes each is prone to.
The same data in three formats
Seeing identical content side by side makes the philosophical differences obvious. Here is a small service configuration expressed in each format.
JSON
{
"service": {
"name": "api-gateway",
"port": 8080,
"tls": true,
"hosts": ["a.example.com", "b.example.com"]
}
}
YAML
service:
name: api-gateway
port: 8080
tls: true
hosts:
- a.example.com
- b.example.com
TOML
[service]
name = "api-gateway"
port = 8080
tls = true
hosts = ["a.example.com", "b.example.com"]
JSON leans on braces and quotes; YAML uses indentation and dashes; TOML uses INI-style key-value pairs grouped under bracketed tables. You can move between them with a converter such as the YAML ↔ JSON or TOML ↔ JSON converter when migrating an existing file.
JSON: the interchange default
JSON (JavaScript Object Notation) is a strict, minimal format built for data interchange between systems. It maps cleanly onto the primitive types most languages share — objects, arrays, strings, numbers, booleans, and null — and parsers exist in virtually every runtime. Because the grammar is small and unambiguous, JSON parses predictably and is the natural choice for APIs, log lines, and machine-to-machine payloads.
The same minimalism that makes JSON reliable makes it awkward for hand-edited config. Standard JSON has no comments, forbids trailing commas, and requires every string key to be double-quoted. A misplaced comma in a large file produces a parse error with little context. Some ecosystems work around this with JSON with Comments (JSONC), used by editors like VS Code, but JSONC is a superset that ordinary JSON parsers will reject. For validating or pretty-printing JSON before committing it, a JSON formatter catches structural mistakes quickly.
YAML: human-friendly, with sharp edges
YAML (YAML Ain't Markup Language) was designed to be read and written by people. It supports comments with #, anchors and aliases for reusing blocks, multi-document files separated by ---, and block scalars for embedding multi-line strings. A useful fact: YAML 1.2 is a strict superset of JSON, so any valid JSON document is also valid YAML, which is why many tools accept either interchangeably.
That expressiveness comes at a cost. YAML's reliance on significant whitespace means a single misaligned space can silently change nesting or break a parse. Its implicit type coercion is the most notorious trap — the so-called "Norway problem," where unquoted no, yes, on, and off are interpreted as booleans under YAML 1.1, so a list of country codes containing NO turns into false. Bare numbers, dates, and values like null are similarly auto-typed. The defense is to quote any string that could be misread.
When YAML's features actually pay off
YAML earns its complexity in large, layered configuration where comments and reuse matter: Kubernetes manifests, CI pipeline definitions, and Ansible playbooks all lean on it. If your config is small and flat, those features are dead weight and a stricter format is safer. We cover that tension in more depth in when JSON beats YAML.
TOML: built specifically for config
TOML (Tom's Obvious, Minimal Language) was created to be an obvious config format with clear semantics and no whitespace sensitivity. It supports comments, has first-class types for integers, floats, booleans, strings, and dates, and uses explicit table headers like [server] and [[products]] (an array of tables) to express structure. Indentation is purely cosmetic, so reformatting a TOML file cannot change its meaning.
TOML reads naturally for flat or shallowly nested data, which is why it anchors several language toolchains — Rust's Cargo.toml and Python's pyproject.toml are the most visible examples. Its weakness is the opposite of YAML's: deeply nested structures get verbose and harder to follow because every level needs an explicit table path. For configuration that is mostly key-value with a few sections, TOML hits a sweet spot of readability and predictability.
Side-by-side comparison
| Aspect | JSON | YAML | TOML |
|---|---|---|---|
| Comments | No (standard) | Yes (#) | Yes (#) |
| Whitespace significant | No | Yes | No |
| Native date type | No | Yes | Yes |
| Superset of JSON | — | Yes (1.2) | No |
| Best for deep nesting | Good | Good | Awkward |
| Implicit type coercion | No | Yes (a hazard) | No |
| Typical home | APIs, data interchange | K8s, CI, Ansible | Cargo, pyproject |
How to choose
Match the format to the job rather than to a preference. The decision usually comes down to who edits the file and how nested the data is.
- Choose JSON when machines produce and consume the file — API requests and responses, structured logs, cached state — or when you need a parser guaranteed to exist everywhere. Accept that humans will find it tedious to edit by hand.
- Choose TOML for hand-edited application and tool configuration that is mostly flat or has a handful of clear sections. You get comments and explicit types without whitespace fragility.
- Choose YAML when you need comments, block reuse, or multi-document files, and the surrounding ecosystem expects it. Quote ambiguous strings, and lean on a schema or linter to catch indentation and coercion bugs early.
A practical rule: do not introduce YAML's complexity unless you are using its distinctive features. If you only need key-value pairs with sections, TOML is simpler and safer; if a machine is the only reader, JSON is the most portable.
Validate and convert before you commit
Whatever format you land on, validate the file before it reaches production — a config that fails to parse at startup is a preventable outage. Run YAML and TOML through a parser locally, and pretty-print JSON to confirm it is well-formed. When you inherit a file in one format and your stack wants another, convert it rather than rewriting by hand: the JSON ↔ YAML Advanced converter and the JSON formatter handle the round trip and flag malformed input. If you are weighing config formats against binary serialization for performance-sensitive paths, see JSON vs Protobuf vs MessagePack.
Frequently Asked Questions
Yes. As of the YAML 1.2 specification, any valid JSON document is also valid YAML, which is why many parsers and tools accept either format interchangeably. The reverse is not true, since YAML's indentation syntax and comments are not legal JSON.
Under YAML 1.1, unquoted values like no, yes, on, and off are coerced to booleans, so the country code NO becomes false. Quoting any string that could be misread as a boolean, number, or null avoids the issue.
Standard JSON does not allow comments. Some tools support a JSON with Comments (JSONC) superset, but ordinary JSON parsers will reject those files, so do not rely on comments for interchange data.
TOML has clear, unambiguous semantics, supports comments and explicit types, and is not whitespace-sensitive, which makes hand-edited config predictable. Cargo.toml and pyproject.toml are the prominent examples.
Yes. Because all three map to similar data structures, converters handle the round trip reliably. Try the YAML ↔ JSON converter at /tools/yaml-json or the TOML ↔ JSON converter at /tools/toml-json for migrating an existing file.