YAML vs JSON for Config: Which One Should You Use?
Pick almost any modern tool and you will hit a configuration file. Kubernetes manifests, GitHub Actions workflows, Docker Compose, ESLint settings — some use YAML, some use JSON, and a few accept both. Choosing between them is less about taste than about who reads the file and how often a human edits it by hand.
Here is a grounded comparison of the two formats, the traps that bite people, and a simple rule for deciding.
The same data in both formats
Start with a small server config so the shapes are side by side. First JSON:
{
"server": {
"host": "localhost",
"port": 8080,
"tls": false
},
"features": ["search", "export"]
}Now the equivalent YAML:
server:
host: localhost
port: 8080
tls: false
features:
- search
- exportSame structure, fewer symbols. YAML drops the braces, quotes, and most commas. That reduction is the entire pitch for YAML — and also the root of most of its surprises.
Comments
This is the biggest everyday difference. JSON has no comments. The spec simply does not include them, so you cannot leave a note next to a tricky setting without a parser that supports a nonstandard extension like JSONC.
YAML supports comments with a hash:
port: 8080 # fallback port, overridden by PORT env varFor a file a human maintains, comments matter a lot. Being able to explain why a value is set the way it is often saves the next person an hour of guessing.
Whitespace sensitivity
JSON does not care about indentation. You can minify it to one line and it parses the same. YAML cares deeply. Indentation defines structure, and it must be spaces — tabs are not allowed. Mixing two spaces here and four spaces there, or sneaking in a tab, produces errors that are hard to spot because the file still looks fine to your eye.
A classic mistake is a misaligned list item:
features:
- search
- export # extra space, now this breaksIn large YAML files, indentation bugs are the number one cause of frustration. JSON trades verbosity for never having to think about this.
JSON is a subset of YAML
A useful fact: YAML 1.2 is a strict superset of JSON. Any valid JSON document is also valid YAML, which means a YAML parser can read your JSON files directly. This is why many tools accept both without extra code. It also gives you an escape hatch — if a YAML block gets confusing, you can drop into inline JSON-style syntax inside the same file:
features: ["search", "export"]
server: { host: localhost, port: 8080 }The Norway problem
Here is the trap that catches everyone eventually. YAML tries to be helpful by guessing types. Unquoted words that look like booleans get converted. In YAML 1.1, which many parsers still follow, these all become true or false:
enabled: yes
debug: no
active: on
locked: offThe famous case is country codes. The code for Norway is NO, so this:
countries:
- NO
- SE
- FIparses the first entry as the boolean false instead of the string NO. The fix is to quote anything you want kept as text:
countries:
- "NO"
- "SE"
- "FI"Numbers have a related issue. A version string like 1.20 may be read as the number 1.2, dropping the trailing zero. When in doubt, quote. JSON never does this guessing — a string is a string because it has quotes, full stop.
Anchors and reuse
YAML has a feature JSON lacks: anchors and aliases, which let you define a block once and reference it elsewhere. An anchor is marked with an ampersand, and an alias pulls it back in with an asterisk:
defaults: &defaults
timeout: 30
retries: 3
staging:
<<: *defaults
host: staging.example.com
production:
<<: *defaults
host: example.comThe merge key pulls the shared defaults into each environment. This keeps repeated config DRY, but it also makes files harder to read for newcomers and some parsers disable it for safety. Use it sparingly.
When to pick each
The deciding question is who touches the file. Choose JSON when a machine produces or consumes it: API request and response bodies, data interchange between services, build artifacts, anything programmatic. Its rigidity is a feature there, and nearly every language parses it natively with no dependency.
Choose YAML when a human edits it regularly: application config, CI pipeline definitions, infrastructure manifests. Comments and the lighter syntax pay off, and the type-guessing traps are manageable once you know to quote ambiguous values.
A reasonable default: data on the wire goes in JSON, config a person maintains goes in YAML. When you need to move between them while debugging, convert rather than retype.
Related tools: