DEVESSENTIALS

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

YAML, JSON, and TOML are the three dominant formats for configuration files and structured data in modern software. They overlap significantly — all three can represent the same data — but each has a different philosophy about readability, strictness, and use case. Choosing the wrong one causes unnecessary friction.

The Same Data in All Three Formats

# YAML
server:
  host: localhost
  port: 8080
  debug: true

database:
  url: postgres://localhost/mydb
  pool_size: 10
  timeout: 30

features:
  - auth
  - analytics
  - billing
// JSON
{
  "server": {
    "host": "localhost",
    "port": 8080,
    "debug": true
  },
  "database": {
    "url": "postgres://localhost/mydb",
    "pool_size": 10,
    "timeout": 30
  },
  "features": ["auth", "analytics", "billing"]
}
# TOML
[server]
host = "localhost"
port = 8080
debug = true

[database]
url = "postgres://localhost/mydb"
pool_size = 10
timeout = 30

features = ["auth", "analytics", "billing"]

Feature Comparison

FeatureYAMLJSONTOML
Comments✅ Yes (#)❌ No✅ Yes (#)
Trailing commasN/A❌ Not allowedN/A
Multiline strings✅ Block scalars (| and >)⚠️ With \n escape✅ Triple-quoted strings
Indentation-sensitive✅ Yes (spaces only)❌ No❌ No
Explicit types⚠️ Implicit (with gotchas)✅ Yes✅ Yes
Native date type✅ Yes❌ No (string)✅ Yes (RFC 3339)
Anchors / aliases✅ Yes (&anchor, *alias)❌ No❌ No
Multi-document files✅ Yes (---)❌ No❌ No
Spec complexity⚠️ Very complex (80+ pages)✅ Simple✅ Moderate
Human writability✅ Good (once learned)⚠️ OK (verbose)✅ Very good
Machine readability✅ Good✅ Excellent✅ Good

When to Use YAML

YAML is the right choice when configuration is written by humans, deeply nested, and benefits from comments. It's the dominant format in the DevOps and cloud-native ecosystem:

  • Kubernetes — all resource manifests (Deployments, Services, ConfigMaps)
  • Docker Composedocker-compose.yml
  • GitHub Actions — workflow files in .github/workflows/
  • GitLab CI.gitlab-ci.yml
  • Ansible — playbooks and inventory files
  • Helm — chart values and templates

YAML's anchors and aliases (&anchor / *alias) let you reuse values across the file — useful in large CI configs where many jobs share the same base configuration.

# YAML anchors — reuse a base configuration
defaults: &defaults
  image: node:20
  timeout: 30
  retry: 2

build:
  <<: *defaults  # merge all keys from defaults
  script: npm run build

test:
  <<: *defaults
  script: npm test

Gotcha: YAML uses indentation for structure — tabs are not allowed, only spaces. A single misplaced space can change the meaning or cause a parse error. Always validate YAML before deploying it.

When to Use JSON

JSON is the right choice when the data is machine-generated, consumed by an API, or needs to be universally parseable:

  • REST APIs — request and response bodies
  • package.json — Node.js project manifest
  • tsconfig.json — TypeScript configuration (supports comments via JSONC)
  • GeoJSON, OpenAPI specs — standardized data exchange formats
  • Database storage — JSON columns in PostgreSQL, MySQL
  • Configuration when schema validation is important — JSON Schema is the most mature tooling

JSON's biggest advantage is universal support — every programming language has a built-in JSON parser. Its biggest weakness is verbosity (all strings must be quoted, no comments) and strict syntax (no trailing commas).

When to Use TOML

TOML is the right choice when you need a human-friendly, unambiguous format for application configuration:

  • RustCargo.toml (project manifest and dependencies)
  • Pythonpyproject.toml (packaging, linting, testing config)
  • Hugo — static site configuration
  • Gitea, Forgejo — server configuration
  • Any new project where you control the config format

TOML is explicitly typed, non-indentation-sensitive, and has no implicit type conversion surprises. It maps cleanly to a hash table and is easy to parse. The section-based syntax [section] and [[array_of_tables]] is intuitive for flat-to-moderate nesting.

# TOML — explicit types, no indentation required
[package]
name = "my-app"
version = "1.0.0"
authors = ["Alice <alice@example.com>"]
edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }

[[servers]]
name = "production"
host = "prod.example.com"
port = 443

[[servers]]
name = "staging"
host = "staging.example.com"
port = 8443

The YAML Norway Problem

One of YAML 1.1's most infamous quirks: unquoted NO was parsed as the boolean false, causing country: NO (Norway's ISO code) to become country: false. Similarly, yes, on,off, true, false — and their capitalized variants — were all treated as booleans.

# YAML 1.1 (PyYAML, many older tools) — dangerous implicit conversions
country: NO          # parsed as false  ← the Norway problem
enabled: yes         # parsed as true
debug: on            # parsed as true
value: 1_000_000     # parsed as 1000000 (octal-like underscores)
version: 1.0         # parsed as float, not string

# Fix: always quote values that could be misinterpreted
country: "NO"
enabled: "yes"
version: "1.0"

YAML 1.2 (2009) removed most of these implicit conversions, but many tools (including PyYAML until version 6.0) still use YAML 1.1 parsing by default. Always quote string values that look like booleans, numbers, or null.

Quick Decision Guide

SituationUse
API request/response bodyJSON
Node.js project manifestJSON (package.json)
TypeScript configJSON/JSONC (tsconfig.json)
Kubernetes / Docker / CI pipelineYAML
Ansible playbooksYAML
Rust project configTOML (Cargo.toml)
Python project configTOML (pyproject.toml)
Static site config (Hugo)TOML
New project — you choose the formatTOML (safest) or YAML (if deeply nested)
Schema-validated configJSON (best tooling support)

Need to validate or convert between formats? YAML Validator · JSON Formatter · YAML to JSON converter

Frequently Asked Questions

Can YAML parse JSON?

Yes — valid JSON is also valid YAML, since YAML 1.2 is a superset of JSON. A YAML parser can read a JSON file without any changes. This is useful in systems that support YAML configuration: you can write your config as JSON if you prefer, and the YAML parser will handle it. The reverse is not true: YAML files often use syntax (anchors, multiline strings, unquoted values) that JSON parsers cannot read.

Why does YAML have a reputation for being error-prone?

Several reasons. First, YAML uses indentation for structure, so a misplaced space causes a parse error or silently changes the data. Second, YAML has many implicit type conversions: 'yes', 'on', 'true', 'True' all become the boolean true in YAML 1.1 (common in older tools like PyYAML). 'Norway problem': the country code 'NO' was parsed as false. Third, YAML's spec is very complex — over 80 pages — with many edge cases. YAML 1.2 fixed most of the implicit conversion issues, but many tools still use 1.1 parsers.

What is the difference between TOML and INI format?

TOML is inspired by INI but is more structured. INI has no standard spec and no support for nested data, arrays, or typed values — everything is a string. TOML has a formal specification, supports typed values (integers, floats, booleans, dates, arrays, inline tables), and supports nested tables. If you've outgrown INI and want something human-friendly without YAML's indentation traps, TOML is the natural upgrade.

Why does Kubernetes use YAML instead of JSON or TOML?

Kubernetes manifests started as JSON (the API is JSON-based) but YAML became the preferred format for human-authored config because it's less noisy — no closing braces, no quotes on most strings, and comments are supported. YAML's support for multi-document files (multiple resources separated by ---) also fits Kubernetes well. The downside is that YAML's indentation sensitivity causes many user errors, which is why tools like Helm and kustomize exist to generate YAML programmatically.

Is TOML better than YAML for configuration?

For many use cases, yes. TOML has less syntax ambiguity, explicit types, a simpler spec, and no indentation-sensitive structure. It's especially well-suited to flat or moderately nested configs like Cargo.toml, pyproject.toml, or Hugo config files. YAML remains better for deeply nested data (like Kubernetes manifests) and for systems where the config is primarily generated by machines rather than written by hand. If you're choosing between them for a new project's config format, TOML is usually the safer pick for human-authored files.