TOML to JSON Converter
Convert TOML to JSON or JSON to TOML with tables, dotted keys and all four datetime types handled honestly — entirely on this device.
TOML integers past 9007199254740992 lose digits when JSON.parse reads them: keep the digits as a JSON number, or write them as a quoted string. TOML nan, inf and -inf have no JSON form — refuse the conversion, or write null and name it in the notes.
Press ? for shortcuts
Do it offline:$ python3 -c "import tomllib,json,sys;print(json.dumps(tomllib.load(sys.stdin.buffer)))" < Cargo.toml
How to use it
- Drop a file, pick one, or paste TOML straight in — nothing leaves this device, and the badge names the format.
- Choose how the JSON should read: two spaces, four spaces or compact, and whether large integers keep their digits or arrive quoted.
- Read the counts under the result — dropped comments, stringified date-times, big integers — measured on this run.
- Copy the result, save it with the extension the direction implies, or press Share to fold both panes into a link.
Paste a Cargo.toml, pyproject.toml or netlify.toml and read it back as JSON, or paste JSON and get TOML — the badge names the direction and you can pin it. Dotted keys become nested objects, doubled headers become arrays, and a 64-bit integer keeps every digit. Whatever the target format cannot hold is counted under the result. Up to 2 MB, on this device.
How it works
A TOML file is one table. Section headers like [package] open a sub-table, a dotted key writes the same nesting on a single line, and a header written twice with double brackets — [[bin]] — is the only way TOML spells a list of tables. Those three spellings are different text for one shape, and all arrive as ordinary objects and arrays.
The type list differs at both ends. TOML has four date-time kinds and JSON has none, so each one leaves as an ISO 8601 string and the local kinds keep no Z. TOML integers are signed 64-bit while JSON numbers are doubles, so anything past ±2^53 is printed digit for digit and flagged. And nothing in TOML means null, which the reverse direction has to resolve.
Examples
# workspace manifest
[package]
name = "ithomia"
edition = "2021"
metadata.docs.all-features = true
[[bin]]
name = "cli"
path = "src/main.rs"
[[bin]]
name = "worker"
path = "src/worker.rs"
{
"package": {
"name": "ithomia",
"edition": "2021",
"metadata": {
"docs": {
"all-features": true
}
}
},
"bin": [
{
"name": "cli",
"path": "src/main.rs"
},
{
"name": "worker",
"path": "src/worker.rs"
}
]
}One dotted key builds two levels of object, and the two [[bin]] headers build one array of two members. One line is reported: 1 comment dropped — JSON has no comment syntax.
released = 1979-05-27T07:32:00Z
local = 1979-05-27T07:32:00
day = 1979-05-27
alarm = 07:32:00
precise = 1979-05-27T07:32:00.999999Z
max_i64 = 9223372036854775807
mask = 0xdead_beef
{
"released": "1979-05-27T07:32:00.000Z",
"local": "1979-05-27T07:32:00.000",
"day": "1979-05-27",
"alarm": "07:32:00.000",
"precise": "1979-05-27T07:32:00.999Z",
"max_i64": 9223372036854775807,
"mask": 3735928559
}Edge case. All four date-time kinds print as strings and the three local ones stay offset-free; the microseconds are truncated. The hexadecimal mask arrives in base ten; the 64-bit ceiling survives as 1 integer beyond ±2^53 emitted with every digit intact — double-based JSON parsers will round them.
{
"name": "ithomia",
"servers": [
{ "host": "edge-1" },
{ "host": "edge-2" }
],
"port": 8080
}
name = "ithomia"
port = 8080
[[servers]]
host = "edge-1"
[[servers]]
host = "edge-2"
The other way round, the array of objects becomes two doubled headers — and port moved above them, because a header swallows every line after it. One line records that: key order changed in 1 table — TOML tables must follow the plain keys of their parent.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Three spellings, one object
a.b.c = 1, [a.b] with c = 1 under it, and an inline { c = 1 } all produce the same object. The JSON cannot say which you wrote.
Doubled headers nest as well as repeat
[[a.b]] written twice lands as an array under a.b, not at the root. A header with no keys under it, such as [flags], is a real empty object.
Local date-times never gain a Z
1979-05-27T07:32:00 goes out with no offset invented, a bare 07:32:00 becomes 07:32:00.000, and fractional seconds are read to the millisecond — counted, as always.
Integers arrive in base ten whatever base you wrote
0xdead_beef, 0o755 and 0b1011 all print as decimal numbers, underscores gone. Past ±2^53 the digits are kept unless you switch large integers to quoted. JSON has one number type, so a whole-valued float — 1.0, 1e3 — prints as 1 and 1000 and returns a TOML integer.
nan and inf stop the run by default
JSON spells neither, so the run refuses and points at the value. Set non-finite handling to null if your consumer expects that.
Four JSON shapes have no TOML form
A null, a root that is an array or a bare scalar, an integer outside signed 64-bit, and an array mixing objects with scalars. The first three refuse with the path named; the fourth converts inline, counted.
Common errors
Trying to redefine an already defined table or value at line 3, column 1 — probable cause: the same key or table is defined twice; TOML forbids redefinition.- Two identical [table] headers, a repeated bare key, or a dotted key reopening a table already written out. Merge or rename — the line points at the second definition, not the first.
Trailing comma in an inline table at line 1, column 14 — probable cause: TOML 1.0.0 allows a trailing comma in arrays but never in inline tables; delete the comma.- Arrays tolerate the dangling comma most formatters add; inline tables never do. Some parsers let it through and stricter ones reject the file, so it is refused here too.
`server.tls` is null — TOML has no null value; drop the key or switch null handling to "omit".- API responses and generated config are full of keys held open with null, and TOML cannot write one down. Remove the key, give it a value, or let the omit option drop it and report the path.
A TOML document must be a table — the value converts to a scalar or an array at the top level; wrap it in a key to convert.- A JSON file starting with [ or holding one bare number has no TOML form: every TOML file is key-value pairs. Wrap the payload in a named object and it converts.
FAQ
Can I go from JSON back to TOML on this page?
Yes. Paste JSON and the badge flips by itself; press s to pin the direction by hand. There is no second address for the reverse trip.
Why did my hex mask turn into a long decimal number?
JSON numbers have one notation. 0xdead_beef is read as the integer it denotes and printed as 3735928559 — the same value in the only base JSON writes.
Are the comments in my pyproject.toml preserved?
No — no serializer here keeps them. They are counted before they go, so keep the original file as the source of truth and treat the converted text as output.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Run the conversion; large pastes wait for this.
- ⌘/Ctrl + S
- Download the result as .json or .toml.
- ⌘/Ctrl + C
- Copy the result while nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the result even mid-selection.
- s
- Flip the direction; undo puts it back.
- t
- Step to the next colour theme.
- ? or ⌘/Ctrl + /
- Show this list of keys.
- Esc
- Close the top overlay; nothing resizes.