Write the same configuration in both formats and the difference speaks for itself:
{
"name": "devtul",
"port": 8080,
"features": ["json", "yaml"],
"database": { "host": "localhost", "ssl": true }
}
name: devtul
port: 8080
features:
- json
- yaml
database:
host: localhost
ssl: true
YAML drops the quotes, the commas and the braces. The price is that it is extremely sensitive to indentation.
Where JSON wins
- No ambiguity. The grammar is small enough to state in a few hundred words, every language ships a parser, and no implementation disagrees with another.
- Forgiving about whitespace. Minified to one line or spread over fifty, the meaning is identical. Merge conflicts are also easy to read.
- Fast to parse. Nearly every language has a native or accelerated implementation.
The downsides: it is verbose to write, it has no comments, and multi-line strings are awkward.
Where YAML wins
- It reads cleanly. In deeply nested configuration the eye moves through YAML much faster.
- Comments. This matters more than it sounds — coming back six months later, you can still see why a setting was chosen.
- Multi-line strings.
|preserves line breaks and>folds them, which is invaluable for embedded scripts or certificates. - Anchors and aliases. Define a block with
&nameand reuse it with*nameinstead of repeating yourself.
Where YAML bites
YAML's expressiveness is both its strength and the source of its problems.
1. Bad indentation is a syntax error
Spaces or tabs, and how many, must be consistent throughout the file. An editor that renders a tab as four columns while storing \t produces the classic "looks aligned, fails to parse" situation.
2. Implicit type conversion
This one does the most damage:
country: NO # not the string "NO" — the boolean false
version: 1.20 # not the string "1.20" — the number 1.2
time: 12:30 # parsed as 750 (sexagesimal)
yes_no: yes # the boolean true
Country codes, version numbers, time strings — unquoted, they are silently turned into something else. The rule that saves you is simply quote anything you are unsure about.
3. Parsers do not agree on the edges
The YAML specification is large, and implementations in different languages cover different amounts of it. Some edge-case documents parse in one and fail in another.
Choosing
| Situation | Use | Why |
|---|---|---|
| API requests and responses | JSON | Unambiguous, fast, consistent ecosystem |
| Kubernetes / CI pipeline config | YAML | Already the de facto standard, and comments are needed |
| Data interchange and storage | JSON | Types are explicit; nothing gets guessed |
| Configuration humans edit often | YAML | Readability and comments matter more |
| Lots of repeated blocks | YAML | Anchors remove a great deal of duplication |
A pragmatic middle ground: store JSON internally, hand people YAML with a validation step in front of it. Plenty of toolchains work exactly that way, converting YAML to JSON at build time before passing it downstream.
To move between the two, the JSON ⇄ YAML converter does it in either direction. Afterwards, glance at your numbers and booleans — version fields especially — to make sure nothing changed type behind your back.