JSON vs YAML: When Each One Actually Makes Sense
Both formats can represent the same data — objects, arrays, strings, numbers, booleans, null — so a debate over "which is better" misses the point a little. They're optimized for different situations, and most real projects end up using both, just for different kinds of files.
JSON: unambiguous, and every language already speaks it
JSON's whole design goal is having exactly one way to write anything, with no ambiguity — every parser produces the same result from the same input. It's also universal: every mainstream programming language has JSON support built in or a first-class library, no exceptions. This is why JSON dominates anywhere machines are the primary reader — API responses, data interchange between services, config that's generated programmatically rather than hand-edited. Its downsides only show up when a human has to write or read it directly: no comments (there's no syntax for them at all), and mandatory quoting and bracket-matching that gets genuinely hard to track by eye once nesting gets a few levels deep.
YAML: built for a human to write and read it
YAML strips away JSON's punctuation in favor of indentation, drops quotes for most everyday strings, and adds comments — all changes aimed squarely at making the file pleasant for a person to hand-edit. This is why YAML dominates configuration that a human actually writes and revisits: CI/CD pipelines, Kubernetes manifests, Docker Compose files, application config. The tradeoff is real, though: YAML's flexibility creates several ways to write the same value, and its indentation-based nesting is strict about consistency in a way that produces genuinely confusing parse errors when a tab sneaks in among spaces, or an indent level shifts by one column partway through a block.
The famous YAML gotchas
YAML's permissive type inference is the source of most of its reputation for surprising behavior. An unquoted yes or no gets parsed as a boolean in YAML 1.1 (the version most tools still implement), not the string "yes" — which has bitten more than one person hardcoding a country code of NO (Norway) into a config file and getting false back instead. Unquoted version-looking values like 3.10 can get parsed as a number and silently lose the trailing zero, becoming 3.1 — a real problem for a Python or Node version pin in a CI config. The fix is always the same: quote anything that's meant to stay a literal string but happens to look like a number or boolean to YAML's parser.
What YAML can express that JSON can't
Anchors and references (&name to define a reusable block, *name to reference it, <<: *name to merge it into another mapping) let a YAML file define a value once and reuse it in several places without repeating it — genuinely useful in configs with a lot of structural repetition, like several CI jobs sharing the same base environment settings. JSON has no equivalent; converting YAML with anchors to JSON resolves them into their fully expanded form, which is usually fine for the resulting data but does mean the JSON version loses the "single source of truth" structure the YAML had.
A practical rule of thumb
If a human is going to open the file in an editor and change values by hand on a regular basis, YAML's comments and lighter syntax are worth the stricter indentation rules. If the file is generated and consumed entirely by code — an API payload, a data export, anything that's never meant to be hand-edited — JSON's lack of ambiguity is worth more than YAML's readability, since there's no human readability need to trade off against it in the first place.
Convert between them
FreeToolDev's JSON ↔ YAML converter handles both directions, including multiple YAML documents separated by --- converting to a JSON array in one pass — useful for a bundled Kubernetes manifest or CI config with several documents in a single file.