TOML to JSON
Nothing is uploaded: this converter parses TOML 1.0 in your browser and emits JSON. Tables become objects, [[array of tables]] entries become arrays of objects, RFC 3339 datetimes are kept as strings, and duplicate keys fail with a line-numbered error instead of being silently merged. The JSON follows RFC 8259.
TOML to JSON explained
TOML owns a specific niche: it is the configuration format of Cargo.toml, pyproject.toml and a hundred package managers, chosen because a human can edit it without breaking it. JSON owns a different one — it is what programs exchange. Sooner or later a script, a test fixture or an API wants your TOML as JSON, and that crossing has exactly two mechanical questions: how does a [table] header become a JSON object, and how does a [[array of tables]] header become a JSON array?
The mapping is deterministic. A [table] and its keys become a nested object; dotted keys such as database.port become nested objects too; a [[array of tables]] becomes an array with one object per header. TOML's scalars map directly — booleans stay booleans, integers and floats stay numbers, and the underscores TOML allows for readability vanish, because 1_000_000 and 1000000 are the same number. RFC 3339 datetimes have no JSON type, so they arrive as strings with their text preserved exactly.
Everything runs in this browser tab. The TOML text you paste is parsed by an in-page engine, the JSON is serialised from the parsed document, and neither touches a network — open DevTools and watch the Network panel stay silent while you convert. The page's Content-Security-Policy forbids outbound connections, so the privacy claim is checkable rather than decorative.
Round-tripping is the common workflow — pull config out of a payload, edit it, put it back — and the convert JSON back to TOML page runs this mapping in reverse, scalars first.
The JSON this tool emits is compact by default, so if you want it indented for reading, the JSON formatter will re-print it with your choice of spacing.
How the conversion actually works
The engine parses your TOML into a document tree first, because every JSON decision follows from TOML's own scoping rules: a [table] header opens a named object, a [[array of tables]] header appends a new object to a named array, and keys above any header belong to the root object. Once the tree exists, emitting JSON is a straight serialisation — the only judgement calls are the places TOML and JSON disagree, and each is decided the same way every time:
- Tables: [owner] with a name key produces an owner object — TOML's headers and JSON's braces encode the same nesting.
- Arrays of tables: each [[servers]] header appends one object to a servers array, in file order.
- Dotted keys: database.port = 5432 nests under database, exactly as TOML 1.0 defines dotted keys to behave.
- Datetimes: 1979-05-27T07:32:00Z has no JSON type, so it is emitted as the string "1979-05-27T07:32:00Z", byte for byte.
- Numbers: underscores are TOML punctuation, not data — 1_000_000 emits as 1000000 — and TOML's inf and nan become null, because JSON has no literals for either.
What the output looks like
The worked example below is the exact pair the converter's Load sample button produces: a root with three scalar keys (one of them underscored), an [issuer] table, and two [[items]] entries. Watch each shape cross — the underscores vanish inside the number, the issuer table nests as an object, and the items array collects its objects in file order. Keys stay in the order the TOML declared them, because document order is the only order a converter can keep honestly.
Because the JSON is emitted from the parsed tree rather than by textual splicing, formatting is normalised too: two spacing styles in the TOML produce one consistent JSON, and a stray blank line changes nothing. What survives is structure and values — which is exactly what a converter should promise.
Duplicate keys and other honest failures
An honest converter refuses inputs it cannot represent faithfully, and TOML 1.0 is strict enough that refusals are rare and unambiguous. Three inputs are rejected with a specific, line-numbered message instead of being silently reshaped:
- Duplicate keys — TOML 1.0 forbids defining a key more than once, so the parser stops at the offending line rather than letting last-one-wins quietly rewrite your config.
- Multi-line strings — this parser's supported subset covers single-line basic and literal strings; a """ block is refused with a message that says exactly that, instead of a mangled guess.
- Unclosed constructs — a [table] header or quoted string that never ends reports the line where the parser gave up, not a generic syntax error.
The mapping at a glance
Every construct this converter supports, and where it lands in the JSON:
| TOML 1.0 | JSON out |
|---|---|
| [owner] table | Nested "owner" object |
| [[items]] header | "items" array of objects |
| database.port dotted key | Nested "database" object |
| 1979-05-27T07:32:00Z | String, RFC 3339 text preserved |
| 1_000_000 | Number 1000000 |
| 'literal string' | String, backslashes untouched |
Frequently asked questions
Does converting TOML to JSON upload my file anywhere?
No. Parsing and serialisation both run inside this browser tab with JavaScript that loaded when the page opened. There is no API route to send data to, and the Content-Security-Policy blocks outbound connections. You can verify both claims in seconds: open DevTools, watch the Network panel while you convert, and see that no request fires.
What happens to TOML datetimes in the JSON output?
They become strings. JSON (RFC 8259) has no date or datetime type — only string, number, boolean, null, object and array — so 1979-05-27T07:32:00Z is emitted as the exact string "1979-05-27T07:32:00Z". Nothing is reformatted or timezone-shifted; the text survives byte for byte, and your downstream code parses it when it needs a real date.
How does [[array of tables]] differ from [table]?
Double brackets append, single brackets define. [servers] creates one object named servers; a second [servers] header would be a duplicate-key error. [[servers]] creates an array and appends one object per header, so three [[servers]] blocks become a three-element array. The single-versus-double distinction is the whole difference, which is why this converter preserves it in the reverse direction too.
Why is a duplicate key an error instead of an override?
Because TOML 1.0 declares that defining a key multiple times is invalid, and a converter that resolved the clash would certify a file its own specification rejects. The error cites the line number of the second definition, which is usually the typo or the bad merge you needed to find anyway.
My TOML uses triple-quoted multi-line strings — why the error?
This parser supports a documented subset of TOML 1.0: single-line basic strings, single-line literal strings, integers, floats, booleans, datetimes, tables, arrays of tables and dotted keys. Multi-line strings are outside the subset and are rejected with a clear named message rather than parsed partially. Split the value into a single-line string with \n escapes and it converts cleanly.
What happened to my inf and nan values?
TOML allows floating-point inf and nan, but JSON has no literals for either — JSON.parse cannot produce them and JSON.stringify writes null. The converter emits null for those two values and flags them in the preview, because silently turning infinity into a finite-looking number is the kind of lie that costs hours to trace.
Which related tools should I use next?
- JSON to TOMLConverter — runs in your browserOpen
- JSON FormatterIndent, sort keys and strip comments with configurable output.Open
- JSON ValidatorValidate syntax with exact line and column, and repair it in one click.Open
- What Is JSONPlain-English guideOpen
- JSON vs YAMLHead-to-head comparisonOpen
- JSON ToolsCompare, format, validate and explore JSON documents.Open