JSON vs YAML for Config Files: Pick the Right Tool, Skip the Pain
A practical guide to choosing between JSON and YAML for configuration files, with concrete gotchas and recommendations for Kubernetes, APIs, and more.
Every project hits the same fork in the road: JSON or YAML? Both are everywhere, both look simple, and both have foot-guns that will ruin a Friday deploy if you pick wrong. Here's how I decide.
The Short Version
JSON is a data interchange format that happened to get used for config. YAML is a config format that happens to be a superset of JSON. That's the whole story — and it explains every tradeoff that follows.
If a machine is the primary author, use JSON. If a human is the primary author, use YAML. If both, pick based on which mistakes you can afford.
Where JSON Wins
JSON's strictness is its superpower. There's exactly one way to write an object, one way to write a string, and the parser will slap you for trailing commas. That's great when you're generating payloads programmatically or shipping API responses where deterministic output matters.
- API request and response bodies — every HTTP client and server speaks it natively.
- Package manifests (
package.json,composer.json) — small, structured, machine-edited most of the time. - Serialization between services — no ambiguity, no locale surprises.
- Anything stored in a database as a blob —
jsonbcolumns in Postgres exist for a reason.
The lack of comments hurts, yes. But if your config file is so complex that it needs paragraphs of explanation, your config file is the problem.
Where YAML Wins
YAML is written for humans who edit by hand. The indent-based syntax, anchors for reuse, and multi-line strings are genuinely useful when a single file might be 400 lines and touched by six different people.
- Kubernetes manifests — the ecosystem assumes YAML, period.
- CI pipelines (GitHub Actions, GitLab CI, CircleCI) — readable, diff-friendly.
- Ansible playbooks — imperative-ish flows read better with YAML's flow.
- Docker Compose — multi-service config with shared fragments via anchors.
The tradeoff: YAML has opinions about your keys. Strong ones.
The Gotchas That Will Bite You
YAML's "human friendly" design means it tries to guess what you meant. Sometimes it guesses wrong.
The Norway Problem
countries:
- NO # parsed as false
- SE
- DK
The classic. NO, YES, ON, OFF, TRUE, FALSE — all coerced to booleans in YAML 1.1. Country codes, feature flags, enum strings — any of them can silently flip. Always quote strings when the content could look like anything else.
Indent Sensitivity
Tabs are forbidden. Mixing two-space and four-space indentation inside one file will either error or silently re-parent a block. JSON doesn't care about whitespace; YAML cares a lot.
Anchors and Aliases
YAML lets you define a chunk once and reuse it:
Powerful. Also opaque — someone reading this for the first time has to mentally expand the anchor to know what the actual config is. Use sparingly.
JSON's No-Comment Problem
You want to leave a note for the next developer? You can't. The closest workaround is a dummy key:
It's ugly. It also survives programmatic round-trips, unlike YAML comments in many parsers.
Trailing Commas
JSON doesn't allow them. JSON5 and JSONC do. If your editor auto-formats with trailing commas and you paste into a strict JSON parser, things break at runtime, not at save time.
Side-by-Side
- Strict, predictable, no ambiguity
- Universal parser support
- No comments (workarounds are ugly)
- Verbose for deeply nested config
- Great for machines, okay for humans
- Trailing commas invalid
- Readable, supports comments
- Anchors and references for DRY config
- Indent-sensitive, whitespace matters
- Implicit type coercion (the Norway problem)
- Slower parsers, bigger dependency footprint
- Great for humans, okay for machines
Recommendations by Use Case
| Use Case | Pick | Why |
|---|---|---|
| Kubernetes manifests | YAML | Ecosystem, readability, anchors |
| API request/response | JSON | Interop, strict schema |
| CI pipeline definitions | YAML | Hand-edited, benefits from comments |
package.json style manifests | JSON | Tool-managed, deterministic diffs |
| App runtime config (12-factor) | JSON or env vars | Parsing simplicity |
| Docker Compose | YAML | Standard, plus anchors |
| Secrets at rest | Neither (use a vault) | Both will leak if committed |
| LLM structured output | JSON | Models are trained on it, stricter grammar |
Converting Between Them
Round-tripping is fine for pure data, but you lose YAML comments and anchors when you convert to JSON. Going from JSON to YAML is safer — you just get a less compact version of the same tree.
When I need to check a YAML file for a sneaky type coercion, I convert it to JSON and inspect the actual parsed values. A "NO" that becomes false is immediately obvious once quotes are gone.
And for the reverse — I pretty-print and validate JSON before committing it. Syntax errors in a 400-line config are easier to spot when braces line up.
The Meta Rule
Pick the format that matches who edits the file most. If it's humans, YAML — and quote your strings. If it's code, JSON — and don't fight it with comments. The worst outcome is a team that can't agree, so half the project is JSON and half is YAML with no rule for which goes where.
Pick once, document the choice, move on.
Try these tools
More articles
How to Merge PDFs in Your Browser Without Uploading Them Anywhere
Why client-side PDF merging matters for privacy, how pdf-lib works under the hood, and the limitations you need to know before trusting a browser tool.
Why Client-Side Image Compression Matters for Your Page Weight and LCP
When to compress images in the browser versus on a server, how WebP, AVIF, and JPEG actually compare, and the Lighthouse wins that follow.