JSON vs YAML vs TOML: Choosing a Config File Format
A practical comparison of JSON, YAML, and TOML for configuration files — readability, strictness, tooling support, and which to choose for different use cases.
Written by Alex · Developer & Founder
Solo developer based in Adelaide, Australia. Built MyEasyTools to make everyday file and text tasks faster and free for everyone.
Get more from MyEasyTools — No ads, higher limits, faster processing
Work through the examples yourself with our free tool
Try JSON Formatter →Config files touch every part of software development: CI/CD pipelines, package manifests, application settings, infrastructure definitions. The format you choose affects readability, error risk, tooling support, and how easy the config is to maintain. This guide compares JSON, YAML, and TOML across the dimensions that matter in practice.
Quick comparison
| Dimension | JSON | YAML | TOML |
|---|---|---|---|
| Comments | No | Yes | Yes |
| Trailing commas | No | N/A | N/A |
| Multiline strings | Cumbersome | Clean | Clean |
| Whitespace significance | No | Yes (indentation) | No |
| Parse complexity | Simple | Complex | Moderate |
| Spec version issues | Stable | YAML 1.1 vs 1.2 differences | Stable |
| First-class null/bool | Yes | Tricky (implicit) | Yes |
| Tooling maturity | Universal | Mature | Growing |
JSON
JSON was designed for data exchange, not human authoring. Its strictness (no comments, no trailing commas, mandatory double quotes) is a feature for data interchange and a frustration for configuration files.
Best at:
- Config that's generated by code and consumed by code
- Any context where a human-writable, human-readable format isn't required
- Environments where universal parser support matters (
package.jsonmust work everywhere)
Pain points:
- No comments — you can't document why a setting exists
- Trailing commas cause parse failures (the most common JSON config error)
- Nested structures become heavily indented and hard to scan
Real example — npm package.json:
{
"name": "myapp",
"version": "1.0.0",
"scripts": {
"build": "next build",
"dev": "next dev"
},
"dependencies": {
"next": "^14.0.0"
}
}
JSON works fine here because package.json is half machine-generated (by npm commands) and half human-edited, in a context where tooling (editors, package managers) provides strong support.
JSONC (JSON with Comments): VS Code's settings use JSONC — a non-standard extension that allows // comments. Standard JSON parsers reject JSONC, so this is useful only in tools that explicitly support it.
I use JSON for config that's generated programmatically or consumed by APIs. For anything a human writes regularly, I prefer YAML or TOML.
YAML
YAML ("YAML Ain't Markup Language") is the dominant config format for infrastructure tooling: Docker Compose, Kubernetes, GitHub Actions, Ansible, CircleCI. If you're working with any of these, you're writing YAML.
Best at:
- Infrastructure and CI/CD configuration (the whole industry uses YAML here)
- Config with multiline strings (shell commands, queries, content blocks)
- Config that needs inline comments for documentation
Pain points:
- Whitespace significance: indentation errors cause subtle bugs without obvious error messages
- YAML 1.1 vs 1.2 differences: the old
yes/noambiguity in 1.1 (parsed as booleans) is fixed in 1.2, but some tools still use 1.1 - The "Norway problem": in YAML 1.1, country codes like
NOorOFFare parsed as boolean false. This breaks ISO country code configs without quoting. - Complex spec: YAML has features (anchors, aliases, custom types) that make advanced config powerful but also introduce parser complexity
Real example — GitHub Actions:
name: Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: npm run build
# TODO: add deployment step
YAML works well here. The indentation structure maps cleanly to job/step hierarchies, and inline comments document intent.
YAML anchors (the & and * syntax) allow DRY config by defining a block once and reusing it. For large Kubernetes manifests with repeated service definitions, this is genuinely useful.
TOML
TOML ("Tom's Obvious Minimal Language") was created specifically for config files. It has a clear spec, no whitespace significance, and maps intuitively to a hash table structure.
Best at:
- Rust project config (
Cargo.toml) - Python project metadata (
pyproject.toml) - Application settings files where humans will read and write regularly
- Config with sections (TOML's table syntax is cleaner than nested YAML or JSON)
Pain points:
- Less universal tooling than JSON/YAML (though major languages all have libraries)
- Less industry adoption outside Rust/Python ecosystems
- Arrays of tables (
[[products]]) can be unintuitive at first
Real example — Rust Cargo.toml:
[package]
name = "my-app"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
# Build-only dependencies
[build-dependencies]
build-script-utils = "0.1"
TOML's section headers ([package], [dependencies]) are flat and scannable in a way that nested JSON or YAML isn't. The inline tables ({ version = "1.0", features = ["derive"] }) read naturally.
Choosing for your project
| Use case | Recommendation |
|---|---|
| npm/Node.js package manifest | JSON (ecosystem standard) |
| GitHub Actions, Docker Compose | YAML (ecosystem standard) |
| Kubernetes manifests | YAML (ecosystem standard) |
| Rust project config | TOML (ecosystem standard) |
| Python project metadata | TOML (PEP 518/517 standard) |
| Application settings file | TOML or YAML (preference) |
| API request/response body | JSON (universal) |
| Documentation/CMS config | YAML (comments, multiline) |
For application settings (feature flags, environment-specific config, tool configuration): TOML if your language has good library support; YAML if you need multiline strings or comments are critical.
If you're writing a new tool and choosing the format from scratch, TOML is my preference for human-authored config: no whitespace traps, clean syntax, comments, and no ambiguous booleans.
For working with JSON config files — validating, formatting, or understanding complex nested structures — use our JSON Formatter to pretty-print and validate the content before debugging.
FAQ
Can I use comments in JSON config files? Standard JSON doesn't support comments. In practice, some tools (VS Code settings, TSConfig) use JSONC (JSON with Comments), but standard parsers reject it. If you need comments in a JSON config, consider switching to TOML or YAML for that file.
Why does YAML use whitespace instead of brackets? YAML was designed to be human-readable first. The author found brackets and braces visually noisy and wanted indentation to carry the structure. It works well for shallow hierarchies; deeply nested YAML can become error-prone.
Are there security risks with YAML?
Yes — YAML parsers that support arbitrary type deserialization can be exploited to execute code via deserialization attacks. In Python, yaml.load() is dangerous; yaml.safe_load() is the correct function. Always use the safe loading function in languages that expose a choice.
What's the difference between TOML and INI files?
INI is an older, unstandardised format with key=value pairs and [section] headers. TOML formalises and extends this concept with typed values, nested tables, and arrays. TOML is INI with a proper spec.
Can I convert between JSON, YAML, and TOML programmatically? Yes — any of these formats can be parsed into an in-memory hash map and serialised to any of the others. The conversion is lossless for most data structures, with the exception that comments, anchors, and order-sensitive content in YAML/TOML may not survive a round-trip through a generic converter.