If you've worked with Kubernetes, Docker Compose, or GitHub Actions, you've used YAML. If you've consumed any REST API, you've worked with JSON. And at some point, you've almost certainly needed to convert one to the other.
Here's everything you need to know about YAML ↔ JSON conversion — what works, what doesn't, and the gotchas that trip up developers.
YAML and JSON represent the same data
Both formats encode the same underlying data structures: objects (key-value maps), arrays, strings, numbers, booleans, and null. This means any YAML document can be represented in JSON — and vice versa — with a few important exceptions.
Same data, two formats:
# YAML
name: nginx-pod
replicas: 3
ports:
- 80
- 443
debug: false
{
"name": "nginx-pod",
"replicas": 3,
"ports": [80, 443],
"debug": false
}
YAML is a superset of JSON
Here's a fact that surprises most developers: valid JSON is also valid YAML. YAML 1.2 was explicitly designed as a superset of JSON. This means any JSON file can be parsed by a YAML 1.2 parser without modification.
The reverse isn't universally true. YAML has features that JSON doesn't support:
-
Comments — YAML supports
# commentsyntax; JSON has no comments -
Anchors and aliases — reuse values with
&anchorand*alias -
Multi-line strings — literal block (
|) and folded block (>) styles - Bare strings — values without quotes in most contexts
When you convert YAML to JSON, these features are either inlined (anchors resolved) or dropped (comments lost).
The tricky parts: YAML type coercion
YAML 1.1 (the version most YAML parsers were based on until recently) has aggressive type coercion rules that can surprise you:
# These are BOOLEANS in YAML 1.1:
enabled: yes
debug: no
active: on
verbose: off
# This is an OCTAL number in YAML 1.1:
permissions: 0755 # → 493 in decimal
If you convert this YAML to JSON with a YAML 1.1 parser, yes becomes true and 0755 becomes 493 — not what you wanted.
YAML 1.2 fixes this: only true/false/null are special keywords. If you're dealing with legacy config files, quote the values you want to stay as strings: enabled: "yes".
Comments disappear — by design
This is the most common complaint about YAML-to-JSON conversion:
# Production database
database:
host: db.prod.example.com # Never use localhost here
port: 5432
After converting to JSON, every comment is gone. This isn't a bug — it's fundamental. JSON has no comment syntax, and comments aren't part of the data model. They're metadata attached to the source text.
Practical advice: keep YAML as your source of truth for config files you edit by hand. Generate JSON from YAML as a build step, not a manual workflow. That way you always have your comments.
YAML anchors expand on conversion
YAML anchors let you reuse values:
defaults: &defaults
timeout: 30
retries: 3
production:
<<: *defaults
host: prod.example.com
staging:
<<: *defaults
host: staging.example.com
When converted to JSON, anchors are fully resolved:
{
"defaults": {"timeout": 30, "retries": 3},
"production": {"timeout": 30, "retries": 3, "host": "prod.example.com"},
"staging": {"timeout": 30, "retries": 3, "host": "staging.example.com"}
}
The deduplication is gone, but the data is identical.
When to use YAML vs JSON
| Use case | Format |
|---|---|
| Config files (Kubernetes, Docker, CI) | YAML |
| API requests and responses | JSON |
| Infrastructure as code | YAML |
| Database storage | JSON |
| Files humans edit directly | YAML |
| Inter-service communication | JSON |
| Package manifests (npm, cargo) | JSON or TOML |
Quick reference: convert in your browser
Need to convert a YAML manifest to JSON right now? Try the free YAML ↔ JSON Converter — two-way conversion, live preview, copy or download the output. Nothing leaves your browser.
Paste any YAML and get clean JSON instantly:
$ cat deployment.yaml | pbcopy # copy to clipboard
# paste into the tool, get JSON output
Or in a terminal with Python:
python3 -c "import sys, json, yaml; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))" < config.yaml
And the reverse (JSON → YAML):
python3 -c "import sys, json, yaml; print(yaml.dump(json.load(sys.stdin), default_flow_style=False))" < data.json
Common conversion errors and fixes
"mapping values are not allowed here" — you have an unquoted colon inside a string value. Fix: wrap the value in quotes.
# Broken
description: Use port 8080: it's the default
# Fixed
description: "Use port 8080: it's the default"
"tab characters must not be used in indentation" — YAML requires spaces for indentation, never tabs. Your editor may be inserting tabs. Check your .editorconfig or editor settings.
"found duplicate key" — You have the same key twice in a mapping. JSON doesn't allow duplicate keys either; one value wins depending on the parser.
Numbers becoming strings or strings becoming numbers — YAML tries to infer types. If you need a numeric string like "0755", quote it explicitly.
Understanding the YAML/JSON boundary is one of those things that pays off constantly in DevOps and backend work. Once you know the rules, the conversions are predictable and the gotchas stop being surprising.
Top comments (0)