Developer FIELD NOTES · 4 MIN READ
TOML to JSON: Seeing Your Config File as Data
Tables become objects, [[blocks]] become arrays, datetimes become strings — the translation rules between TOML and JSON, both directions.
Open almost any modern repository and a TOML file is sitting there — pyproject.toml, Cargo.toml, netlify.toml — while the same project's APIs, logs and test fixtures all speak JSON. The two formats describe exactly the same thing: a tree of keys and values. A converter is therefore a translator between two dialects, and the translation rules are stricter than they first look.
One idea: TOML is a spelling of a hash table
TOML was designed so that every document maps unambiguously onto a hash table — the structure JSON calls an object. That single design decision is why conversion is mostly renaming: = instead of :, bare keys instead of quoted ones, section headers instead of nesting. This TOML:
name = "my-app"
[server]
host = "0.0.0.0"
port = 8080
becomes exactly this JSON, pretty-printed with two-space indent:
{
"name": "my-app",
"server": { "host": "0.0.0.0", "port": 8080 }
}
No information is added or lost on the way across — the converter parses the TOML into an in-memory value tree, then serializes that same tree with JSON's punctuation.
Three table shapes, three JSON shapes
TOML has three ways to introduce structure, and each maps to a different JSON shape. A table header like [server] creates (or merges into) an object. An array-of-tables header like [[servers]] appends an object to an array — write the block twice and you get "servers": [ { … }, { … } ], a real JSON array of objects. An inline table like point = { x = 1, y = 2 } stays a compact JSON object on one line. Plain arrays such as tags = ["a", "b"] carry across untouched.
The values that change shape
Most scalars survive intact: booleans, floats, negative numbers, arrays of them. But TOML has niceties JSON lacks, and each is resolved on the JSON side. Integer syntax like underscores and radix prefixes is normalized — 1_000 becomes 1000 and 0xff becomes 255, because JSON has no way to write either. Date and time literals are kept as strings: TOML's 2026-10-24T09:30:00Z arrives in JSON as "2026-10-24T09:30:00Z", since JSON has no native date type. That string convention is what makes a clean round-trip possible — the same text turns back into the same TOML datetime literal.
Going backwards: JSON to TOML
The reverse direction runs the same pipeline the other way. Scalars become key = value lines; nested objects become [table] headers; arrays of objects become [[array-of-tables]] headers; deeply nested objects become dotted header paths (deep.a under a [deep] parent). Strings are emitted as single-quoted literal strings where possible — name = 'my-app' — falling back to double-quoted basic strings with escaping when the content contains a single quote.
One constraint bites: only a JSON object can become TOML. A TOML document's root is always a table, so a top-level array like [1, 2, 3] or a bare scalar has no TOML representation and is rejected with a clear error rather than a silently mangled file. Wrap it in an object first.
What never survives the trip
Comments are the clearest casualty. # deploy target is syntax for humans, not data, so conversion drops it — and a round-trip TOML → JSON → TOML does not restore it. Formatting is re-canonicalized too: blank-line placement, key order and indentation come from the serializer, not your original file. If the comments are the point, keep the TOML file as the source of truth and treat JSON as a read-only view. (Why TOML has comments and JSON deliberately does not is one of the fault lines compared in YAML vs TOML vs JSON; the JSON grammar itself is covered in JSON explained.)
Try it yourself
Paste a real pyproject.toml or Cargo.toml into the TOML to JSON Converter, note how [[blocks]] become JSON arrays, then flip the Direction toggle and send the JSON back — an object-root document round-trips cleanly. To see the third member of the config-language family, convert the same data with the JSON to YAML Converter, and run a YAML file through the YAML Validator to appreciate how much looser a format can be while still parsing.