All posts
tutorials

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.

July 5, 20268 min read
Alex

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 MyEasyToolsNo 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.json must 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/no ambiguity 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 NO or OFF are 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.

Get more from MyEasyToolsNo ads, higher limits, faster processing