YAML vs JSON vs TOML: Choosing the Right Config Format
Every project needs configuration, and the three dominant formats — YAML, JSON, and TOML — each have strong opinions behind them. This guide compares all three so you can pick the right one for your project, or at least understand why your toolchain chose it for you.
The Same Config in Three Formats
Let's start with a practical example — the same configuration expressed in each format:
JSON
{
"server": {
"host": "0.0.0.0",
"port": 8080,
"debug": false
},
"database": {
"url": "postgres://localhost:5432/myapp",
"pool_size": 10,
"ssl": true
},
"allowed_origins": [
"https://example.com",
"https://staging.example.com"
]
} YAML
server:
host: "0.0.0.0"
port: 8080
debug: false
database:
url: "postgres://localhost:5432/myapp"
pool_size: 10
ssl: true
allowed_origins:
- https://example.com
- https://staging.example.com TOML
[server]
host = "0.0.0.0"
port = 8080
debug = false
[database]
url = "postgres://localhost:5432/myapp"
pool_size = 10
ssl = true
allowed_origins = [
"https://example.com",
"https://staging.example.com",
] Feature Comparison
| Feature | JSON | YAML | TOML |
|---|---|---|---|
| Comments | No | Yes (#) | Yes (#) |
| Trailing commas | No | N/A | Yes |
| Multi-line strings | No (use \n) | Yes (| and >) | Yes (""") |
| Date/time type | No (string only) | Yes (implicit) | Yes (RFC 3339) |
| Indentation-sensitive | No | Yes | No |
| Spec complexity | Simple (~6 pages) | Complex (~80 pages) | Moderate (~20 pages) |
| Nesting depth | Unlimited | Unlimited | Awkward beyond 2-3 levels |
JSON: The Universal Exchange Format
Strengths
- Universal support — every programming language has built-in JSON parsing. It's the lingua franca of web APIs.
- Unambiguous — the spec is tiny and there's only one way to represent data. No surprises.
- Great tooling — validators, formatters, and converters everywhere. Use our JSON Formatter to instantly beautify JSON config files.
- Machine-readable — ideal for data exchange between services.
Weaknesses
- No comments — the single biggest complaint. You can't explain why a setting exists.
- Verbose — all those quotes and braces add visual noise for humans.
- No trailing commas — adding an item to the end of a list requires modifying the previous line too, creating noisy diffs.
- No multi-line strings — embedding SQL queries or templates is painful.
Best for
API responses, data exchange, package.json, tsconfig.json, any config that's primarily machine-generated or consumed. Also see our guide on common JSON errors if you're editing JSON config by hand.
YAML: The Human-Friendly (But Treacherous) Format
Strengths
- Clean syntax — minimal punctuation makes it pleasant to read and write.
- Comments — explain why settings exist with
# inline comments. - Multi-line strings — the
|(literal) and>(folded) operators handle long text gracefully. - Anchors and aliases — reduce repetition with
&anchorand*aliasreferences.
Weaknesses
- Indentation is semantic — a single misplaced space can change the meaning of your config. Tabs are forbidden.
- Implicit type coercion —
yes,no,on,offare parsed as booleans.3.10becomes3.1. The stringNObecomesfalse. This has caused real production incidents. - Complex spec — YAML 1.2 is ~80 pages. There are features most developers never learn (document markers, complex keys, flow mappings).
- Security risks — YAML deserializers can execute arbitrary code in some languages. Always use safe loading functions.
The Norway Problem
The most infamous YAML gotcha: country codes like NO (Norway) are parsed as boolean false. Versions of Node.js have been listed as 3.10 and parsed as 3.1 in CI configs. Always quote strings that could be misinterpreted.
# DANGEROUS — "NO" becomes false
country: NO
# SAFE — quotes force string type
country: "NO" Best for
Kubernetes manifests, Docker Compose, CI/CD configs (GitHub Actions, GitLab CI), Ansible playbooks — anywhere the ecosystem has already chosen YAML for you. Convert between formats easily with our JSON-YAML Converter.
TOML: The Configuration-First Format
TOML (Tom's Obvious, Minimal Language) was created specifically for configuration files, learning from JSON's and YAML's weaknesses. For a deeper dive, see our guide on what TOML is and why it's replacing YAML.
Strengths
- Designed for config — not data exchange or document markup. Every feature serves configuration needs.
- No indentation sensitivity — sections use explicit
[headers], so whitespace is purely cosmetic. - No type coercion surprises — strings must be quoted, booleans are only
true/false. No "Norway problem." - Native date/time support —
created = 2026-03-09T10:30:00Zis a first-class type. - Trailing commas allowed — cleaner diffs when adding items to arrays.
Weaknesses
- Deep nesting is awkward — TOML uses dotted keys (
[server.database.primary]) that become unwieldy beyond 2-3 levels. - Smaller ecosystem — fewer tools and less IDE support compared to JSON and YAML.
- Less familiar — developers need to learn a new syntax.
Best for
Application configuration files: Cargo.toml (Rust), pyproject.toml (Python), hugo.toml (Hugo), netlify.toml. Format and convert TOML with our TOML Formatter.
Decision Flowchart
- Is it an API response or data exchange? → Use JSON.
- Does the tool/framework require a specific format? → Use what it requires (Kubernetes = YAML, Cargo = TOML, npm = JSON).
- Is it a flat or shallow config file you control? → Use TOML.
- Is it a deeply nested config with comments needed? → Use YAML (carefully).
- Do you need maximum language/tool compatibility? → Use JSON.
Migration Tips
If you're converting between formats:
- JSON → YAML: Watch for strings that YAML will misinterpret as other types. Quote anything that looks like a boolean or number.
- YAML → JSON: Comments will be lost. Consider adding a
"_comment"key pattern if documentation is critical. - JSON → TOML: Flatten deeply nested structures. TOML works best with 1-2 levels of nesting.
- YAML → TOML: Replace indentation-based nesting with
[section]headers. Convert anchors/aliases to explicit values.
For JSON-specific comparisons, see our detailed breakdown of JSON vs XML covering when each format wins.
Quick Reference
| Use Case | Recommended Format |
|---|---|
| REST API responses | JSON |
| Kubernetes / Docker Compose | YAML |
| Rust project config | TOML |
| Python project config | TOML (pyproject.toml) |
| CI/CD pipelines | YAML |
| npm / Node.js config | JSON |
| Hugo / static site config | TOML |
| Data serialization | JSON |
Working with config files across formats? Use our JSON-YAML Converter to switch between formats instantly, or validate your JSON configs with our JSON Validator to catch syntax errors before deployment.