TOML vs YAML vs JSON — Config Formats Ranked by How Much They’ll Annoy You
Every config format will eventually betray you. YAML with indentation hell and silent boolean coercions, JSON with its no-comments policy, TOML with its 'wait, what's this syntax?' moment. Here's the realistic breakdown of what each one costs you — and when to pick which.
Every project eventually makes you pick a config format. YAML is everywhere. JSON is older than some of your coworkers. TOML showed up more recently with its hand raised, saying “actually, I was designed for this.” All three will betray you eventually. The betrayals are just different.
Here’s a direct comparison — same config, three formats — followed by exactly when each one will make you regret your life choices.
The Same Config, Three Ways
A basic web app config: name, port, debug flag, version string, database settings, allowed origins. Nothing exotic. This is where the format differences start to show.
Bahasa Indonesia: TOML
# App configuration
[app]
name = "my-app"
port = 3000
debug = false
version = "1.2.3"
allowed_origins = ["https://example.com", "https://api.example.com"]
[database]
host = "localhost"
port = 5432
name = "mydb"
YAML
# App configuration
app:
name: my-app
port: 3000
debug: false
version: "1.2.3"
allowed_origins:
- https://example.com
- https://api.example.com
database:
host: localhost
port: 5432
name: mydb
JSON
{
"app": {
"name": "my-app",
"port": 3000,
"debug": false,
"version": "1.2.3",
"allowed_origins": [
"https://example.com",
"https://api.example.com"
]
},
"database": {
"host": "localhost",
"port": 5432,
"name": "mydb"
}
}
At a Glance
| Fitur | Bahasa Indonesia: TOML | YAML | JSON |
|---|---|---|---|
| Komentar | ✅ Yes | ✅ Yes | ❌ No |
| Type inference | Explicit | Aggressive (often wrong) | Explicit |
| Susunan | = ["a", "b"] | - item or inline | ["a", "b"] |
| Koma di akhir | T/A | T/A | ❌ Illegal |
| Deeply nested configs | Gets verbose fast | Readable-ish | Verbose but unambiguous |
| Spec stability | TOML 1.0 (2021, stable) | 1.1 vs 1.2 parser chaos | Stable |
| Null support | ❌ No null type | ✅ Yes (~ atau null) | ✅ Yes (null) |
| Penggunaan umum | Cargo.toml, pyproject.toml | GitHub Actions, k8s, Docker | package.json, tsconfig.json |
YAML: Most Readable Until It Isn’t
YAML looks great in demos. A flat config reads almost like prose. The trouble starts when you hit one of its edge cases — and by then your config file is already load-bearing infrastructure.
The Norway Problem
In YAML 1.1 — which most parsers still default to — these values are all booleans: y, n, yes, no, on, off, true, false. So country: NO parses as country: false. This is the real reason it’s called the Norway Problem — Norway’s ISO country code is NO. PyYAML fixed this in v6.0 (released 2022). SnakeYAML (used by a lot of Java tooling) still hasn’t fully addressed it. Check your parser before using bare no atau yes in config values.
Type Inference That Guesses Wrong
Unquoted values in YAML get type-coerced. port: 8080 becomes an integer. version: 1.10 becomes the float 1.1 — mathematically equal, semantically wrong. Forget to quote a version string and you’ll spend ten minutes wondering why your app thinks it’s on v1.1 instead of v1.10. The fix is boring: quote everything that should stay a string. But YAML doesn’t force you to, so it doesn’t.
Indentation Is Load-Bearing
Tabs are illegal in YAML — not discouraged, illegal. Mix two-space and four-space indentation within a file and you get a parse error that often points to the wrong line. GitHub Actions is the sharpest edge here: a misindented run: block fails at runtime, not at parse time, because workflow runners only validate syntax, not step structure. You’ll get “unexpected value” from a CI job with no indication of which step broke, and you’ll spend 20 minutes adding debug output before realizing the problem was a two-space indent where four was expected.
If your YAML has become a mess of inconsistent indentation, the YAML Formatter will normalize it before you start debugging.
TOML: The Format That Actually Thought About Config
Tom Preston-Werner (GitHub co-founder) built TOML because he was tired of writing INI-style configs with inconsistent parsing behavior and YAML configs that surprised him. TOML 1.0 landed in January 2021 after years of revisions. It’s now the standard for Rust projects (Cargo.toml), Python packaging (pyproject.toml), and Hugo sites. The spec is stable, the parsers are consistent, and the type system does what you expect.
What It Gets Right
- No surprise type coercions.
version = "1.10"is always a string.port = 3000is always an integer. What you write is what you get. - Comments work exactly like you’d expect (
#to end of line), unlike JSON. - Flat to moderately nested configs are genuinely readable, unlike deeply nested JSON.
The Array-of-Tables Syntax
TOML’s main stumbling block is its array-of-tables syntax. If you want an array of objects — say, multiple database connections — the notation looks like this:
[[databases]]
name = "primary"
host = "db1.example.com"
[[databases]]
name = "replica"
host = "db2.example.com"
mendapatkan bagian yang sama dari ruang yang tersisa setelah jarak dikurangi. Tiga kolom dengan [[double bracket]] section is one item in the databases array. It works. It’s unambiguous. But every developer who opens a TOML file for the first time asks “is this INI?” — because it kind of looks like it. That unfamiliarity has a real cost when you’re onboarding contributors who’ve never seen TOML before.
TOML also has no null type — intentionally. If your schema uses null to mean “key is present but explicitly unset,” you’ll need to model that differently (omit the key entirely, or use a sentinel value). And deeply nested configs become verbose quickly: TOML doesn’t have YAML’s anchor/alias system for reusing subtrees, so there’s a lot of copy-paste if your config has repeated structure.
Itu TOML Formatter is handy when you’re trying to clean up a TOML file that’s grown organically over time.
JSON: The Devil You Know
JSON was designed for data interchange — machines talking to machines — not for humans writing config files. It ended up as a config format because every language already had a JSON parser, and that convenience won. Now we have package.json, tsconfig.json, .eslintrc.json, and approximately 40 other JSON configs in every JavaScript project, all of which you edit by hand.
No Comments. Still.
Douglas Crockford removed comments from JSON intentionally in 2012 — he worried developers would use them as parsing directives (similar to IE’s conditional comments). The internet has complained about this every day since. The workarounds people use:
- JSONC — JSON with Comments. VS Code uses it for
settings.jsondanlaunch.json. Not parseable by standard JSON parsers. Non-standard. - JSON5 — adds comments, trailing commas, unquoted keys, multiline strings. Has a spec and a standalone parser. Babel uses it for configs. Still not standard JSON.
- A
"_comment"key — a string field that holds your comment text. Works. Looks ridiculous. Gets into your data model.
Koma Trailing
Also illegal. Add a trailing comma after the last item in an array or object and JSON.parse throws SyntaxError: Unexpected token } — telling you there’s a problem, but not where the errant comma is. This is the number one JSON parse error in human-authored config files, and it happens because every other modern language (JavaScript arrays, Python lists, Rust enums) allows trailing commas and humans write JSON by hand with the same habits.
What JSON Gets Right
The type system is unambiguous and universal. Every JSON parser in every language agrees on what true, 1, "1"dan null mean. JSON Schema is the most mature config validation option of the three — VS Code uses it to validate tsconfig.json and package.json in-editor, with inline error highlighting. When tooling writes your JSON (webpack, tsc, npm), you don’t care about readability anyway — that’s what the Pemformat JSON is for.
Verdict: Pick Based on Context, Not Preference
Use JSON when tooling generates or consumes it (package.json, tsconfig, AWS configs, GitHub API responses), or when you need JSON Schema validation. Don’t fight it by writing it by hand more than necessary. The lack of comments hurts, but the ubiquity and tooling support are hard to argue with.
Use YAML when the config is primarily human-authored and relatively flat — GitHub Actions workflows, Docker Compose files, Kubernetes manifests. Quote anything that could be mistyped as a boolean or number (version strings, country codes, anything starting with a digit). Run a linter. Never use tabs. Treat type inference as a bug, not a feature.
Use TOML when you control the format choice and want no surprise type coercions. It’s the most honest of the three about what it is. If you’re starting a greenfield project and none of your tooling mandates a format, TOML is the least likely to surprise you six months in. The unfamiliarity is a one-time cost; the explicitness is permanent.
Anda mungkin juga menyukai
Instal Ekstensi Kami
Tambahkan alat IO ke browser favorit Anda untuk akses instan dan pencarian lebih cepat
恵 Papan Skor Telah Tiba!
Papan Skor adalah cara yang menyenangkan untuk melacak permainan Anda, semua data disimpan di browser Anda. Lebih banyak fitur akan segera hadir!
Alat Wajib Coba
Lihat semua Pendatang baru
Lihat semuaMemperbarui: Kita alat terbaru was added on Jun 5, 2026
