YAML and JSON both represent structured data, but they're optimized for different use cases. Here's when to use each and how to convert between them.
At a glance
| JSON | YAML | |
|---|---|---|
| Syntax | Strict, machine-friendly | Flexible, human-friendly |
| Comments | No | Yes (# comment) |
| Quotes | Required for strings | Optional for most strings |
| Indentation | Not significant | Significant (structure) |
| Multi-line strings | Awkward | Clean (` |
| Primary use | API responses, data interchange | Configuration files |
| Supersets | – | JSON is a subset of YAML |
When to use JSON
API responses and requests: JSON is the standard. It's compact, fast to parse, and universally supported. Every language has built-in JSON parsing.
Data storage: When you're storing structured data that will be read by machines (database, message queues, event payloads), JSON's strictness is a feature — less ambiguity means fewer parsing edge cases.
Config files that are code-generated: If a tool writes the config file, JSON's strict format is easier to generate correctly.
When to use YAML
Configuration files humans will edit: YAML's lack of braces and quotes makes it dramatically more readable for humans. This is why Kubernetes manifests, GitHub Actions, Docker Compose, Ansible playbooks, and many other tools use YAML — these files are written and maintained by people.
When you need comments: JSON has no comment syntax. YAML comments ({% raw %}# this is a comment) are essential for documenting configuration options.
Multi-line strings: YAML has clean syntax for literal blocks (|) and folded strings (>):
description: |
This is a multi-line string.
Each line is preserved exactly.
No escaping needed.
folded_description: >
This is a folded string.
These lines will be joined
with spaces into one long line.
The JSON equivalent requires \n escaping:
{
"description": "This is a multi-line string.\nEach line is preserved exactly.\nNo escaping needed."
}
YAML features that JSON lacks
Anchors and aliases (DRY config):
defaults: &defaults
image: node:20-alpine
timeout: 300
build:
<<: *defaults
command: npm run build
test:
<<: *defaults
command: npm test
timeout: 600 # Override defaults
This is impossible in JSON — repeated configuration must be duplicated.
Multiple documents in one file:
---
kind: Deployment
metadata:
name: my-app
---
kind: Service
metadata:
name: my-app-service
Used extensively in Kubernetes to deploy multiple resources from a single file.
YAML boolean traps:
YAML 1.1 (the version many tools use) parses certain strings as booleans:
# These are booleans in YAML 1.1, NOT strings:
enabled: yes # true
disabled: no # false
active: on # true
inactive: off # false
This is a common source of bugs in YAML config. If you mean the string "yes" or "no", quote it:
country: "no" # Norway's country code — NOT a boolean
answer: "yes" # The word "yes" — NOT a boolean
YAML 1.2 (2009+) removed most of these ambiguities, but tool support varies.
Converting between formats
For one-off conversions: A YAML ↔ JSON converter handles the conversion in the browser without any setup.
Python:
import yaml, json
# JSON to YAML
json_str = '{"name": "Alice", "active": true}'
data = json.loads(json_str)
yaml_str = yaml.dump(data, default_flow_style=False)
# YAML to JSON
yaml_str = "name: Alice\nactive: true\n"
data = yaml.safe_load(yaml_str)
json_str = json.dumps(data, indent=2)
# File conversion
with open('config.yaml') as f:
data = yaml.safe_load(f)
with open('config.json', 'w') as f:
json.dump(data, f, indent=2)
JavaScript/Node.js:
const yaml = require('js-yaml');
const fs = require('fs');
// YAML to JSON
const yamlContent = fs.readFileSync('config.yaml', 'utf8');
const data = yaml.load(yamlContent);
const jsonContent = JSON.stringify(data, null, 2);
// JSON to YAML
const jsonContent2 = fs.readFileSync('config.json', 'utf8');
const data2 = JSON.parse(jsonContent2);
const yamlContent2 = yaml.dump(data2);
Command line:
# Python (no dependencies)
python3 -c "import sys, json, yaml; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))" < config.yaml
# Or pipe:
cat config.yaml | python3 -c "import sys, json, yaml; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))"
# yq (the jq for YAML — install: pip install yq or brew install yq)
yq -j '.' config.yaml # YAML to JSON
cat data.json | yq -y '.' # JSON to YAML
YAML pitfalls for developers
Tabs are not allowed for indentation. YAML specifically forbids tabs. If you paste YAML from a source that uses tabs, the parser will error.
Indentation creates structure. Unlike JSON, YAML's structure is defined entirely by indentation. Misalign a key by one space and the structure changes silently.
The Norway problem:
country_codes:
- no # Parses as false (boolean) in YAML 1.1!
- gb
- us
Use quotes: - "no"
Numbers can surprise you:
version: 1.0 # float, not "1.0" string
port: 8080 # integer
hex: 0x1F # integer (31) — if you wanted the string "0x1F", quote it
Practical YAML validation:
Run yamllint before committing config files:
pip install yamllint
yamllint kubernetes/
It catches tab characters, missing blank lines before lists, and other style issues that cause silent parsing problems.
Use JSON for APIs and machine-to-machine data. Use YAML for human-maintained config files where readability and comments matter. When converting between them, be aware of YAML's boolean and number auto-conversion quirks — those are the most common source of conversion bugs.
Top comments (0)