A little help goes a long way. Find a tool/

Developer FIELD NOTES · 5 MIN READ

YAML vs TOML vs JSON: Which Config Format When

YAML, TOML and JSON compared: syntax, the Norway problem, when each format wins for config, and how to convert without losing data.

YAML, TOML, and JSON all do the same job — turn structured data into text a program can read back — but they make opposite bets about who is doing the editing. JSON optimizes for machines, YAML for humans reading deeply nested files, TOML for humans filling in flat settings. Pick the one that matches who (or what) will touch the file most.

One dataset, three dialects

Here is the same configuration in all three formats:

{
  "name": "toolhub",
  "retries": 3,
  "tags": ["fast", "free"],
  "database": { "host": "localhost", "port": 5432 }
}
name: toolhub
retries: 3
tags:
  - fast
  - free
database:
  host: localhost
  port: 5432
name = "toolhub"
retries = 3
tags = ["fast", "free"]

[database]
host = "localhost"
port = 5432

All three load to the same data structure. The differences are ergonomic: JSON quotes everything and braces everything; YAML pushes structure into indentation; TOML replaces one big tree with labeled sections. Notice the quoting rules already differ — in YAML and TOML, plain words like localhost need no quotes, and only "toolhub" needs them because a bare toolhub would be… well, fine too. Strings need quotes only when they could be mistaken for something else — which is both a feature and, as we will see, the source of YAML's most famous bugs.

YAML: indentation is the syntax

In YAML, structure comes from leading spaces. database: opens a nested block; two-space-indented keys beneath it belong to it; - marks a list item. There are no braces to misplace, which makes YAML pleasant to read — and makes a one-space typo a data corruption event, because indenting one line differently changes what it belongs to.

YAML's unquoted scalars are its sharpest edge. Values that look like words are parsed as other types in YAML 1.1 — the versions most tools still ship:

country: no        # parses as boolean false — the "Norway problem"
mode: on           # boolean true
version: 1.10      # number 1.1 — the trailing zero is gone
version: "1.10"    # quoted: the string you meant

The Norway problem (no → false, yes → true, on/off too) and version numbers collapsing (1.10 → 1.1) are legendary in ops circles. The fix is mechanical: quote anything that is semantically a string, even if it looks like a word or a number. On the plus side, YAML has features the others lack: block scalars for multi-line strings (| keeps newlines, > folds them), anchors (&base) and aliases (*base) to reuse a block without repeating it, and multiple documents in one file separated by ---.

TOML: everything is a line

TOML is line-oriented: each line is key = value, and [section] headers define tables. Nesting is spelled out in the header rather than expressed in indentation:

[server]
host = "0.0.0.0"
port = 8080

[server.tls]
enabled = true
min_version = "1.2"

[[products]]        # array of tables — each [[products]] appends one
name = "Hammer"

That explicitness kills YAML's ambiguity bugs: "1.2" is quoted, dates have native syntax (published = 1979-05-27T07:32:00Z), and there is no way for one line to accidentally belong to the wrong parent. The trade-off shows at depth — five nested levels means five header segments ([a.b.c.d.e]) — and lists of complex objects ([[products]]) read more verbosely than YAML's dash lists. That is why TOML dominates flat, setting-style config: Cargo.toml, pyproject.toml, netlify.toml.

So which one, when?

A pragmatic decision rule:

Machine-to-machine → JSON. API payloads, webhooks, log events, anything two programs exchange. Every language parses it natively, the format is strict enough that parsers agree, and strictness is a feature when neither end is human.

Humans editing deeply nested structures → YAML. Kubernetes manifests, GitHub Actions workflows, docker-compose files. Indentation beats bracket-balancing at scale, and list-of-things syntax is clean.

Humans editing flat settings → TOML. Application and package config: databases, build tools, feature flags. Every value on its own line, comments everywhere, no surprises.

And comments decide a lot: YAML and TOML allow them; JSON does not. The JSON-with-comments variants you may meet (JSONC in VS Code settings, JSON5) are convenience dialects, not interoperable standards — do not emit them at an API boundary.

Converting between them without losing data

Conversion is easy in the data, lossy around it. Three things never survive a trip through JSON, because JSON has no way to represent them: comments (gone the moment you convert YAML or TOML to JSON), YAML anchors and aliases (expanded to full copies), and formatting such as multi-line strings, which become \n escapes. Typing can shift too: a YAML version: 1.0 arrives in JSON as the number 1.0, and converting back to YAML drops the trailing zero — if 1.0 is a version string, it needed quotes in the original. Neither format carries binary data; embed small binaries as Base64 strings, which is exactly what the format in How Base64 Encoding Works is for.

The safe workflow is a loop: convert, then validate the result, then spot-check the round trip. A converter will not warn you that your comment died or your no became false — only a validation pass catches those before they reach production.

Try it yourself

Check any YAML document — including those unquoted-scalar gotchas — with the YAML Validator, which parses and reports errors with line numbers. Convert Cargo.toml-style files with the TOML to JSON Converter, and turn an API response into readable YAML with the JSON to YAML Converter — then convert it back and diff, to see exactly what a round trip preserves.

Frequently asked questions

Is YAML a superset of JSON?
YAML 1.2 is: any JSON document is also valid YAML, which is why YAML parsers can read API responses directly. The reverse fails — YAML's indentation-based syntax, anchors, and multi-document streams have no JSON representation, so YAML to JSON loses comments and aliases.
What is the YAML Norway problem?
In YAML 1.1, unquoted yes/no/on/off parse as booleans, so country: no silently becomes country: false. Quote any value meant as a string. YAML 1.2 removed these abbreviations, but many tools still ship 1.1 parsers, so the quoting habit stays.
When should I choose TOML over YAML?
When config is mostly flat settings — key-value pairs, flags, small tables — TOML's line-oriented style is clearer and immune to indentation bugs, which is why Cargo and Python packaging use it. For deeply nested structures with long lists, YAML's dash lists read better than TOML's bracketed headers.
Do comments survive converting YAML or TOML to JSON?
No. JSON has no comment syntax, so every comment is discarded in conversion, and no round trip brings it back. Anchors and aliases are expanded, and multi-line strings become \n escapes. Convert, then validate and spot-check the result before shipping it.
Which format is best for API payloads?
JSON, without much competition. Both ends are programs, every language parses it natively, and its strictness — quoted keys, no trailing commas — means all parsers agree. YAML and TOML are human-editing formats; at a machine boundary they add parser burden and ambiguity for no benefit.