JSON vs YAML vs TOML: Which Config Format Should You Use?
Choosing a configuration format seems trivial until you're six months in, your YAML file has an indentation bug that took two hours to find, or your JSON config is unreadable because it doesn't support comments. This guide compares JSON, YAML, and TOML with real examples so you can pick the right format the first time.
The Same Config in Three Formats
Let's see the same application configuration in all three formats:
JSON
{
"server": {
"host": "0.0.0.0",
"port": 8080,
"debug": false
},
"database": {
"url": "postgresql://localhost:5432/myapp",
"pool_size": 10,
"timeout": 30
},
"features": {
"signup": true,
"dark_mode": true,
"beta_features": ["new_dashboard", "api_v2"]
}
}YAML
# Application configuration
server:
host: "0.0.0.0"
port: 8080
debug: false
database:
url: "postgresql://localhost:5432/myapp"
pool_size: 10
timeout: 30 # seconds
features:
signup: true
dark_mode: true
beta_features:
- new_dashboard
- api_v2TOML
# Application configuration
[server]
host = "0.0.0.0"
port = 8080
debug = false
[database]
url = "postgresql://localhost:5432/myapp"
pool_size = 10
timeout = 30 # seconds
[features]
signup = true
dark_mode = true
beta_features = ["new_dashboard", "api_v2"]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 (strings only) | No (strings only) | Yes (native) |
| Anchors/references | No | Yes (& and *) | No |
| Indentation-sensitive | No | Yes | No |
| Spec complexity | Simple | Complex | Moderate |
| Deep nesting | Easy | Easy | Verbose |
| Human editing | Error-prone | Easy | Easy |
| Machine parsing | Fastest | Slowest | Fast |
Try it yourself: Paste the JSON example above into our JSON Formatter to play with indentation styles, or use the JSON Converter to convert it to YAML and see the difference.
JSON: The Universal Data Format
Strengths
- Universal support. Every programming language has a JSON parser. Every API speaks JSON. Every database supports JSON. No other format comes close in ecosystem support.
- Simple specification. The entire JSON spec fits on a single page. There are no ambiguities, no edge cases, no version differences. A JSON document either parses or it doesn't.
- Fast parsing. JSON parsers are highly optimized. In benchmarks, JSON parsing is typically 5-10x faster than YAML.
- Unambiguous. There's exactly one way to represent any value.
trueistrue, notyes,on,True, orTRUE.
Weaknesses
- No comments. This is JSON's biggest limitation for config files. You can't explain why a setting exists or what values are valid.
- Verbose. Curly braces, square brackets, mandatory double quotes — JSON has more syntax noise than YAML or TOML.
- No trailing commas. Adding an item to the end of a list requires editing two lines (add the comma to the previous line, add the new item). This creates noisy git diffs.
- No multi-line strings. Long strings like SQL queries or HTML templates require
\nescapes, making them unreadable.
Best for
API data exchange, package manifests (package.json, composer.json), data storage, anything that machines read more than humans edit.
YAML: The Human-Friendly Format
Strengths
- Highly readable. Indentation-based structure with no brackets or braces. YAML configs are easy to scan and understand at a glance.
- Comments. Add context, TODOs, and documentation inline with your config.
- Multi-line strings. The
|(literal block) and>(folded block) indicators make long text readable. - Anchors and aliases. Reuse values within the same document using
&anchorand*alias— useful for DRY configs.
Weaknesses
- Indentation bugs. A single wrong space can change your config's meaning silently. Tabs vs. spaces issues are common and hard to see.
- Implicit type coercion. The infamous "Norway problem":
NOis parsed as booleanfalse, not the string "NO". Country codes, version numbers, and time strings can all be misinterpreted. - Complex specification. The YAML spec is over 80 pages. There are multiple ways to write the same thing, leading to inconsistency.
- Security risks. Some YAML parsers support arbitrary code execution via tags like
!!python/object. Always use safe loading (yaml.safe_load()in Python). - Slow parsing. YAML parsers are significantly slower than JSON parsers due to the complex spec.
The Norway Problem
# YAML silently converts these to unexpected types:
countries:
- NO # parsed as boolean false, not string "NO"!
- GB # string "GB" ✓
version: 1.0 # parsed as float 1.0, not string "1.0"
time: 10:30 # parsed as integer 630 (seconds) in YAML 1.1!
# Fix: always quote strings that could be misinterpreted
countries:
- "NO"
version: "1.0"
time: "10:30"Best for
Kubernetes manifests, CI/CD configs (GitHub Actions, GitLab CI), Docker Compose, Ansible playbooks — infrastructure tools where humans edit configs frequently.
TOML: The Config-First Format
Strengths
- Designed for config files. TOML was created specifically for configuration, not general data exchange. Every design decision prioritizes config use cases.
- No indentation sensitivity. Unlike YAML, TOML uses explicit
[section]headers. You can't break your config with a wrong space. - Native date/time types. TOML natively supports dates (
2026-04-27), times (10:30:00), and datetime values without quoting. - Unambiguous. No implicit type coercion. Strings are always quoted, booleans are always
true/false, numbers are always bare. - Comments and trailing commas. Both are supported, making editing easy and git diffs clean.
Weaknesses
- Deep nesting is verbose. TOML's
[section.subsection.subsubsection]syntax becomes unwieldy beyond 2-3 levels. Arrays of tables ([[items]]) are confusing to newcomers. - Smaller ecosystem. Not every language has a battle-tested TOML parser. JSON and YAML have far more tooling support.
- Less adoption. Outside of Rust (
Cargo.toml), Python (pyproject.toml), and Go, TOML is less common than JSON or YAML.
Best for
Application config files, project metadata (pyproject.toml, Cargo.toml), any flat-to-moderately-nested config that humans edit directly.
Debugging config issues? Validate your JSON config with our JSON Validator — it catches trailing commas, missing quotes, and other syntax errors with exact line numbers.
Decision Guide: Which Format Should You Use?
Use JSON when:
- You're exchanging data between systems (APIs, message queues, databases)
- The file is mostly machine-generated and machine-read
- You need maximum compatibility and parsing speed
- You're building a
package.json,tsconfig.json, or similar manifest
Use YAML when:
- The ecosystem requires it (Kubernetes, GitHub Actions, Docker Compose)
- You need deeply nested structures that humans edit frequently
- Comments are essential for understanding the config
- You need multi-line strings (templates, SQL, scripts)
Use TOML when:
- You're writing application config that humans will edit
- The structure is flat or moderately nested (2-3 levels max)
- You want comments without YAML's gotchas
- You need native date/time values
- Your ecosystem supports it (Rust, Python, Go)
Converting Between Formats
Need to convert JSON to YAML or vice versa? Our JSON converter tool handles JSON to YAML conversion. For command-line conversion:
# JSON to YAML (Python)
python -c "import json, yaml, sys; print(yaml.dump(json.load(sys.stdin)))" < config.json
# YAML to JSON (Python)
python -c "import json, yaml, sys; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))" < config.yaml
# JSON to TOML (Python, requires tomli-w)
python -c "
import json, sys
try:
import tomli_w
print(tomli_w.dumps(json.load(sys.stdin)))
except ImportError:
print('pip install tomli-w')
" < config.jsonReal-World Format Choices
| Tool / Platform | Format | Why |
|---|---|---|
| npm / Node.js | JSON | Machine-parsed manifests, universal JS ecosystem |
| Kubernetes | YAML | Deeply nested, human-edited infrastructure configs |
| GitHub Actions | YAML | CI/CD workflows with comments and complex structure |
| Rust (Cargo) | TOML | Project metadata, flat config, no nesting needed |
| Python (pyproject) | TOML | Replaced setup.cfg/setup.py — cleaner config format |
| Docker Compose | YAML | Multi-service definitions with comments |
| VS Code settings | JSONC | JSON with comments — best of both worlds |
| REST APIs | JSON | Universal data exchange format |
| Hugo (static sites) | TOML | Simple site configuration |
A Note on JSON5 and JSONC
If you love JSON's simplicity but need comments and trailing commas, consider these supersets:
- JSON5 — adds comments, trailing commas, single quotes, unquoted keys, hex numbers, and multi-line strings. Used by Babel and webpack.
- JSONC — JSON with comments only. Used by VS Code (
settings.json) and TypeScript (tsconfig.json). Minimal extension, maximum compatibility.
Both parse as standard JSON after stripping the extensions, so they work with existing tooling.
Working with JSON?
Validate, format, and convert your JSON data with our free online tools.
🔗 Related Tools & Resources
Explore these related JSON tools and guides