JSON vs YAML vs TOML: Which Config Format Should You Use?

12 min read

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_v2

TOML

# 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

FeatureJSONYAMLTOML
CommentsNoYes (#)Yes (#)
Trailing commasNoN/AYes
Multi-line stringsNo (use \n)Yes (| and >)Yes (""")
Date/time typeNo (strings only)No (strings only)Yes (native)
Anchors/referencesNoYes (& and *)No
Indentation-sensitiveNoYesNo
Spec complexitySimpleComplexModerate
Deep nestingEasyEasyVerbose
Human editingError-proneEasyEasy
Machine parsingFastestSlowestFast

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. true is true, not yes, on, True, or TRUE.

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 \n escapes, 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 &anchor and *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": NO is parsed as boolean false, 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.json

Real-World Format Choices

Tool / PlatformFormatWhy
npm / Node.jsJSONMachine-parsed manifests, universal JS ecosystem
KubernetesYAMLDeeply nested, human-edited infrastructure configs
GitHub ActionsYAMLCI/CD workflows with comments and complex structure
Rust (Cargo)TOMLProject metadata, flat config, no nesting needed
Python (pyproject)TOMLReplaced setup.cfg/setup.py — cleaner config format
Docker ComposeYAMLMulti-service definitions with comments
VS Code settingsJSONCJSON with comments — best of both worlds
REST APIsJSONUniversal data exchange format
Hugo (static sites)TOMLSimple 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.

We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies. Learn more