YAML vs JSON for Configuration: A Developer's Guide
Compare YAML and JSON for config files — comments, anchors, multiline strings, the Norway problem, and when to convert between the two for your tooling.
If you write configuration for a living, you have met both YAML and JSON, often in the same afternoon. They model the same data — maps, lists, scalars — but the ergonomics differ enough that picking the wrong one creates real pain. This guide walks through the practical trade-offs, the gotchas that bite teams, and how to convert between the two when your tooling demands it.
The same data, two shapes
Both formats describe key-value structures. Here is a small service config in JSON:
{
"service": "billing",
"replicas": 3,
"env": {
"LOG_LEVEL": "info",
"TIMEOUT": 30
},
"regions": ["us-east-1", "eu-west-1"]
}
And the equivalent YAML:
service: billing
replicas: 3
env:
LOG_LEVEL: info
TIMEOUT: 30
regions:
- us-east-1
- eu-west-1
The YAML version is shorter, has no closing braces to balance, and drops most quotes. For files that humans edit by hand all day, that readability adds up.
Where YAML pulls ahead
Comments
JSON has no comments. None. That single limitation is why so many config
ecosystems abandoned it. YAML supports comments with #:
replicas: 3 # bumped for Black Friday traffic
# TODO: move secrets to the vault before launch
env:
LOG_LEVEL: debug
In JSON you are reduced to fake "comment" keys like "_comment": "...", which
clutter the data and confuse parsers.
Multiline strings
Embedding a script or a certificate in JSON means escaping every newline as
\n on one enormous line. YAML offers block scalars that keep text readable.
The | style preserves newlines; the > style folds them into spaces:
startup_script: |
#!/bin/sh
echo "starting"
exec ./server --config /etc/app.yaml
description: >
This long sentence will be folded
into a single line when parsed.
The same startup_script in JSON is one cramped string:
{
"startup_script": "#!/bin/sh\necho \"starting\"\nexec ./server --config /etc/app.yaml"
}
Anchors and aliases
YAML can define a value once and reuse it with anchors (&) and aliases (*),
optionally merging maps with <<. This removes copy-paste from repetitive
configs:
defaults: &defaults
retries: 3
timeout: 30
billing:
<<: *defaults
endpoint: /api/billing
shipping:
<<: *defaults
endpoint: /api/shipping
JSON has no equivalent — you repeat the block every time.
Where JSON pulls ahead
JSON is not the underdog everywhere. It wins on:
- Speed and ubiquity. Every language ships a fast, battle-tested JSON parser. YAML parsers are slower and vary in feature support.
- Determinism. JSON has one obvious way to write most values. YAML has many, and "clever" YAML is hard to review.
- Wire format. APIs speak JSON. You would never send YAML over HTTP as a response body.
- No surprising type coercion — which brings us to the famous gotchas.
The gotchas that bite teams
The Norway problem
YAML 1.1 interprets a long list of bare words as booleans. The country code for
Norway is NO, and unquoted it becomes false:
countries:
- NO # becomes false!
- SE
- DK
enabled: yes # becomes true
shipping: off # becomes false
Parsed, that list silently contains a boolean where you expected a string. The fix is to quote anything that could be misread:
countries:
- "NO"
- "SE"
- "DK"
enabled: true
Numbers that are not numbers
Version strings and zip codes love to lose data. A value like 1.20 becomes the
number 1.2, and a leading-zero zip like 01234 may be parsed as octal or
stripped to 1234. Quote them:
version: "1.20"
zip: "01234"
git_sha: "0e9f8a7"
Indentation and tabs
YAML uses indentation for structure, and tabs are forbidden for indentation. A single stray tab or a misaligned space throws a parse error that points at the wrong line. Configure your editor to insert spaces and show whitespace. JSON, with its explicit braces, sidesteps this entirely.
Trailing-colon and flow ambiguity
A map value that starts with a special character can confuse the parser. When in doubt, quote the scalar. The general rule: YAML's flexibility is exactly what makes it error-prone, so be conservative.
Converting between them for your tooling
Most infrastructure tools accept YAML because humans author it, but they parse it into the same data model as JSON. That means you can convert freely, and you often need to.
Kubernetes manifests are usually YAML, but kubectl and the API server
accept JSON too. When you generate manifests programmatically, emitting JSON and
converting is cleaner:
# pipe a generated JSON manifest through conversion before applying
cat deployment.json | your-json-to-yaml > deployment.yaml
kubectl apply -f deployment.yaml
GitHub Actions workflows are YAML. If a script produces job configuration as JSON, convert it before committing:
{
"name": "CI",
"on": ["push"],
"jobs": {
"test": {
"runs-on": "ubuntu-latest",
"steps": [{ "run": "npm test" }]
}
}
}
That maps directly to a .github/workflows/ci.yml file:
name: CI
on:
- push
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: npm test
Docker Compose is YAML, but if your platform exports service definitions as JSON, the same round-trip applies.
When you need to go either direction, paste your config into the YAML to JSON converter to feed APIs and validators, or the JSON to YAML converter to produce human-friendly manifests. Both preserve structure so you can move between the readable and the machine-friendly form without retyping anything. If you want to confirm the output is well-formed before committing, run it through the JSON validator.
A quick decision guide
- Editing by hand, want comments and reuse, targeting DevOps tools? YAML.
- Sending data over the wire, parsing in code, want speed and zero ambiguity? JSON.
- Generating config in a program but deploying to a YAML tool? Author in JSON, then convert.
Whatever you choose, quote your ambiguous scalars, use spaces not tabs, and keep your anchors readable.
Conclusion
YAML and JSON are two views of the same data: one optimized for humans, one for machines. Knowing the gotchas — the Norway problem, silent number coercion, and indentation traps — lets you use YAML's readability without getting burned. And because they share a data model, converting between them is lossless and quick.
Ready to convert? Drop your config into the YAML to JSON or JSON to YAML tool and ship with confidence. Explore more developer utilities on the JSONPost blog.
Keep reading
Validating JSON with JSON Schema
Learn how JSON Schema works, how to generate a schema from sample data, and how to validate documents with clear, path-based error messages.
JSON vs JSON5 vs JSONC — What's the Difference?
Comments, trailing commas, and unquoted keys — understand JSON5 and JSONC, where each is used, and how to convert them to strict JSON.
How to Format JSON (and Why It Matters)
A practical guide to beautifying, indenting, and minifying JSON — and when to use each, with tips for debugging messy API responses.