TOML vs JSON
TOML vs JSON — Quick Summary
| TOML | JSON | |
|---|---|---|
| Full name | Tom's Obvious, Minimal Language | JavaScript Object Notation |
| Primary use | Config files (Cargo.toml, pyproject.toml) | APIs, config, data interchange |
| Comments | Supported (# comment) | Not allowed |
| Data types | string, integer, float, boolean, datetime, array, table | string, number, boolean, null, object, array |
| Native dates | Yes — RFC 3339 datetimes built in | No — dates are strings by convention |
| Nesting | Tables and arrays of tables | Objects and arrays, unlimited depth |
| Human editing | Designed for hand-editing — minimal punctuation | Workable, but nested braces get noisy |
| Trailing commas | Not an issue — line-based | Syntax error |
| Ecosystem | Rust (Cargo), Python (pyproject.toml), Hugo | Universal — every language and API |
| Best for | Human-maintained config files | APIs, 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 = 3json
{
"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 files — comments, no trailing-comma errors, and dates/times as a native type make TOML far more pleasant to hand-edit than JSON.
- Rust and Python tooling — Cargo.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 generation — JSON is trivial to generate and parse from any language and any API — TOML tooling is comparatively rare outside Rust/Python.
- APIs and data interchange — no HTTP API returns TOML. If two programs need to exchange data, JSON is the default.
- Deeply nested or dynamic structures — JSON's bracket nesting has no practical depth limit; TOML's table syntax gets awkward for deeply nested or array-of-array shapes.