TOML vs JSON

TOML vs JSON — Quick Summary

TOMLJSON
Full nameTom's Obvious, Minimal LanguageJavaScript Object Notation
Primary useConfig files (Cargo.toml, pyproject.toml)APIs, config, data interchange
CommentsSupported (# comment)Not allowed
Data typesstring, integer, float, boolean, datetime, array, tablestring, number, boolean, null, object, array
Native datesYes — RFC 3339 datetimes built inNo — dates are strings by convention
NestingTables and arrays of tablesObjects and arrays, unlimited depth
Human editingDesigned for hand-editing — minimal punctuationWorkable, but nested braces get noisy
Trailing commasNot an issue — line-basedSyntax error
EcosystemRust (Cargo), Python (pyproject.toml), HugoUniversal — every language and API
Best forHuman-maintained config filesAPIs, data exchange between programs

Side-by-Side Example

The same configuration in both formats:

toml
# TOML — built for hand-edited config
title = "My App"

[server]
host = "0.0.0.0"
port = 8080
started = 2024-01-15T10:30:00Z

[database]
hosts = ["db1.example.com", "db2.example.com"]
retries = 3
json
{
  "title": "My App",
  "server": {
    "host": "0.0.0.0",
    "port": 8080,
    "started": "2024-01-15T10:30:00Z"
  },
  "database": {
    "hosts": ["db1.example.com", "db2.example.com"],
    "retries": 3
  }
}

TOML reads closer to an INI file with sections. JSON needs quoted keys and no comments, but every language parses it out of the box.

Parsing in Go

go
// TOML — go get github.com/BurntSushi/toml
import "github.com/BurntSushi/toml"

type Config struct {
    Title    string `toml:"title"`
    Server   struct {
        Host string `toml:"host"`
        Port int    `toml:"port"`
    } `toml:"server"`
}

var cfg Config
_, err := toml.Decode(tomlStr, &cfg)

// JSON — standard library
import "encoding/json"

var cfg2 Config
err = json.Unmarshal([]byte(jsonStr), &cfg2)

When TOML Beats JSON

  • Hand-written config filescomments, no trailing-comma errors, and dates/times as a native type make TOML far more pleasant to hand-edit than JSON.
  • Rust and Python toolingCargo.toml and pyproject.toml are TOML by convention — you'll write it whether you choose to or not in those ecosystems.
  • Documenting intent inline# comments next to a setting explain why a value is set, which JSON can't do without a separate docs file.

When JSON Beats TOML

  • Programmatic generationJSON is trivial to generate and parse from any language and any API — TOML tooling is comparatively rare outside Rust/Python.
  • APIs and data interchangeno HTTP API returns TOML. If two programs need to exchange data, JSON is the default.
  • Deeply nested or dynamic structuresJSON's bracket nesting has no practical depth limit; TOML's table syntax gets awkward for deeply nested or array-of-array shapes.

Frequently Asked Questions

Yes — TOML supports # line comments anywhere, same as YAML. This is one of its main advantages over JSON for hand-maintained configuration.

Yes, via [table] and [table.nested] section headers, or inline tables like server = { host = "x", port = 80 }. Arrays of tables use [[table]] for repeated sections.

TOML, if a human will edit the file directly — comments and native dates make a real difference. JSON is better if the config is only ever read/written by code, since every language parses it natively.

Use JSONKit's TOML to JSON tool to convert TOML into JSON, or JSON to TOML to go the other direction. Both run entirely in your browser.

Related Tools