Every project needs configuration files. Some teams swear by JSON. Others insist on YAML. I've used both extensively across dozens of projects, and the "right" choice depends on your specific situation, team preferences, and use case. Here's what I've learned after years of working with both formats.
The YAML vs JSON debate generates surprising amounts of heat for something as mundane as data serialization formats. But the choice matters more than you might think – it affects maintainability, readability, error rates, and developer happiness.
JSON: The Universal Standard
JSON (JavaScript Object Notation) is everywhere. Every programming language can parse it natively or with a simple library. Browsers understand it. APIs use it. It's the lingua franca of data interchange on the modern web.
JSON's Strengths
- Universal compatibility: Literally every language and platform supports it
- Strict syntax: Unambiguous parsing, fewer edge cases
- Machine-friendly: Easy to generate programmatically
- Browser native: JavaScript's JSON.parse() and JSON.stringify() built-in
- Validation tools: JSON Schema provides robust validation
- Streaming support: Can parse large files incrementally
When JSON Wins
Use JSON for:
- API requests and responses: Industry standard, no debate
- Configuration generated by programs: Easier to write correctly from code
- Data that needs strict validation: JSON Schema is powerful and widely supported
- Small configuration files: Verbosity isn't a problem when files are tiny
- Data interchange between systems: Maximum compatibility
- Browser-based config: Native parsing without libraries
Example JSON configuration:
{
"database": {
"host": "localhost",
"port": 5432,
"name": "myapp",
"pool": {
"min": 5,
"max": 20
}
},
"features": {
"authentication": true,
"analytics": false,
"darkMode": true
},
"cache": {
"enabled": true,
"ttl": 3600
}
}
Clear, unambiguous, machine-readable. No surprises.
YAML: Human-Friendly Configuration
YAML (YAML Ain't Markup Language) was explicitly designed for human readability and writability. No brackets, minimal commas, no quotes (usually). Just clean hierarchical structure through indentation.
YAML's Strengths
- Readable: Cleaner, less cluttered than JSON
- Comments: Native comment support (JSON doesn't have this)
- Multi-line strings: Handles long text elegantly
- Less verbose: No closing brackets or repeated quotes
- Anchors and aliases: DRY (Don't Repeat Yourself) features built-in
- Established in DevOps: Docker Compose, Kubernetes, CI/CD all use YAML
When YAML Wins
Use YAML for:
- Configuration files humans edit frequently: Docker Compose, Kubernetes, CI/CD
- Large configuration files: Conciseness makes big configs manageable
- Configuration needing comments: Document why settings exist
- Multi-line strings: Welcome messages, SQL queries, templates
- Team prefers it: Developer happiness matters
- Infrastructure as code: The ecosystem expects YAML
Same configuration in YAML:
database:
host: localhost
port: 5432
name: myapp
pool:
min: 5
max: 20
features:
authentication: true
analytics: false
darkMode: true
cache:
enabled: true
ttl: 3600
Cleaner, easier to scan, less visual noise.
YAML with Comments and Multi-line
# Database configuration
database:
host: localhost
port: 5432
# Connection pool settings
pool:
min: 5 # Minimum connections
max: 20 # Maximum connections
# Feature flags
features:
authentication: true
analytics: false # Disabled until GDPR compliance
# Welcome message shown to new users
welcome_message: |
Welcome to our application!
This is a multi-line message
that spans several lines
and preserves formatting.
# SQL query for user lookup
user_query: >
SELECT id, name, email
FROM users
WHERE active = true
ORDER BY created_at DESC
Try doing that cleanly in JSON. You can't.
The Gotchas: Where Each Format Hurts
JSON's Pain Points
- No comments: Can't explain why a setting exists. Workarounds feel hacky
- Strict syntax: Forget a comma? Invalid. Trailing comma? Invalid. No mercy
- Verbose: Lots of brackets, quotes, commas. Visual noise in large files
- Multi-line strings: Require escaping newlines. Ugly and hard to read
- No trailing commas: In many languages they're allowed, but not in JSON
- Must quote all keys: Even when unnecessary in JavaScript
Example of JSON pain:
{
"description": "This is a long description that spans multiple lines and needs to be readable but JSON makes it ugly with escaped newlines",
"_comment": "This is a hack for comments",
"items": [
"item1",
"item2",
"item3" // NO TRAILING COMMA ALLOWED
]
}
YAML's Pain Points
- Indentation sensitive: Mix tabs and spaces? Breaks. Wrong indentation? Breaks silently
- Type coercion surprises: `no` becomes boolean false. `012` might be octal. Norway's code `NO` becomes false
- Multiple ways to express same thing: `true`, `True`, `TRUE`, `yes`, `Yes`, `on` all mean true
- Version differences: YAML 1.1 and 1.2 have incompatibilities
- Complex spec: YAML is actually quite complex under the hood
- Harder to generate: Getting indentation right programmatically is annoying
Example of YAML pain:
countries:
norway: NO # Wait, this becomes boolean false!
scotland: off # This also becomes boolean false!
versions:
octal: 012 # This might become 10 in decimal!
string: "012" # Quote it to prevent conversion
booleans:
- yes # true
- Yes # also true
- true # also true
- True # also true
# Inconsistency can confuse
These aren't theoretical. I've hit every one of these bugs in production.
Side-by-Side Comparison
Readability
Winner: YAML – Less visual noise, easier to scan, especially for large files
Writability
Winner: YAML – Fewer characters to type, no need to match brackets
Error-Prone
Winner: JSON – Strict syntax catches errors immediately. YAML can fail silently
Tool Support
Winner: JSON – Better editor support, validation, and formatting tools
Comments
Winner: YAML – Native comments. JSON has none
Machine Generation
Winner: JSON – Easier to generate correctly from code
Portability
Winner: JSON – Works everywhere, truly universal
For Humans
Winner: YAML – More pleasant to read and edit
My Recommendations
After using both extensively, here's when I use each:
Use JSON When
- Building APIs: Request/response bodies should be JSON
- Data interchange: Between systems, languages, platforms
- Browser applications: Native parsing without libraries
- Small configs: Few lines where verbosity doesn't hurt
- Machine-generated: Programs writing config files
- Strict validation needed: JSON Schema is powerful
- Team is uncomfortable with YAML: Don't force tools people don't want
Use YAML When
- CI/CD pipelines: GitHub Actions, GitLab CI, CircleCI expect YAML
- Infrastructure as code: Docker Compose, Kubernetes, Ansible use YAML
- Application config: Database settings, feature flags, app config
- Large config files: Conciseness and comments improve maintainability
- Need comments: Explaining why settings exist is valuable
- Multi-line content: Welcome messages, templates, embedded scripts
- Team prefers it: Developer happiness affects productivity
The Hybrid Approach
Many projects use both. Each format for its strengths. This is totally valid:
my-project/
├── config/
│ ├── database.yml # Human-edited config
│ ├── features.yml # Feature flags with comments
│ └── environments.yml # Environment-specific settings
├── api/
│ ├── requests.json # API examples
│ └── schema.json # JSON Schema validation
├── .github/
│ └── workflows/
│ └── deploy.yml # CI/CD in YAML
└── package.json # Dependency config (JSON standard)
Use JSON for APIs and data. Use YAML for configuration and infrastructure. Each does what it does best.
Best Practices for Each Format
JSON Best Practices
- Use a linter: jsonlint catches syntax errors
- Format consistently: 2 or 4 space indentation, pick one
- Validate against JSON Schema: When structure matters
- Consider JSON5: Allows comments and trailing commas (if tools support it)
- Keep files small: Large JSON files are hard to maintain
- Use consistent key naming: camelCase or snake_case, not both
YAML Best Practices
- Use only spaces, never tabs: Configure editor to convert tabs to spaces
- Configure editor: Show whitespace characters, highlight indentation
- Use yamllint: Catches common mistakes early
- Quote ambiguous strings: "no", "off", "012", "yes" should be quoted
- Be consistent with booleans: Pick true/false and stick with it
- Add comments liberally: That's the whole point of YAML
- Use anchors for DRY: Avoid repeating the same config blocks
YAML anchors example:
defaults: &defaults
timeout: 30
retries: 3
logLevel: info
development:
<<: *defaults
logLevel: debug # Override just this one
production:
<<: *defaults
timeout: 60 # Override just this one
Tooling Support
JSON Tools
- jq: Command-line JSON processor
- JSON Schema: Validation and documentation
- Prettier: Formatting
- ESLint: Linting JSON in JavaScript projects
- Every editor: Built-in JSON support
YAML Tools
- yamllint: YAML linter
- yq: YAML processor (like jq for YAML)
- Prettier: Also formats YAML
- VS Code YAML extension: Excellent editing support
- Red Hat YAML extension: Kubernetes schema validation
Migration Between Formats
Sometimes you need to convert. Both directions work:
# JSON to YAML
cat config.json | yq -y > config.yml
# YAML to JSON
cat config.yml | yq -c > config.json
Most languages have libraries for both formats, so converting in code is straightforward.
The Real Answer
The "JSON vs YAML" debate misses the point. They solve different problems:
- JSON excels at: Data interchange, strict validation, machine parsing, universal compatibility
- YAML excels at: Human editing, configuration files, documentation through comments, readability
Don't pick one and use it everywhere. That's dogma, not pragmatism. Use JSON where precision and universality matter. Use YAML where readability and comments matter.
Let your use case drive the decision:
- API contract: JSON
- Database config file: YAML
- Package manager: JSON (convention)
- CI/CD pipeline: YAML (convention)
- Application config: YAML (comments help)
- Data export: JSON (compatibility)
And if someone tells you one is objectively better than the other in all situations? They haven't used both enough to understand their respective trade-offs. Both have their place. Use the right tool for the job.