TOML and JSON converter
Convert TOML 1.0.0 to JSON or JSON to TOML, with a typed form that keeps integers, floats and dates exact.
A clear answer. Here’s how.
Reads TOML 1.0.0 with a hand-written parser that follows the grammar published with the specification (the ABNF file) and was run against the toml-test conformance suite for 1.0.0: all 208 valid documents give the expected data and all 501 invalid ones are refused (nine of those are byte-level encoding errors that a text box can never deliver, so they are refused when a file is decoded). It handles tables, dotted keys, inline tables, arrays of tables, the four string forms (escapes, the trimmed first newline, line-ending backslashes), integers in four bases with underscores, floats including inf and nan, booleans, and offset date-times, local date-times, local dates and local times. Duplicate keys, a table defined twice and a key reused as a table are errors, reported with a line and column, and so are an integer outside 64 bits and a float too large for 64 bits (neither is silently rounded or turned into infinity). Keys named __proto__ or constructor are ordinary data. TOML 1.1 additions (the \e and \xHH escapes, optional seconds, multi-line inline tables) are not read. A byte-order mark at the start is ignored, a CRLF inside a multi-line string is read as one line feed, and input is limited to 1,000,000 characters, 128 levels of nesting and 200,000 values. JSON has no integer or date types, so the plain form writes integers as numbers up to ±(2^53 − 1) and larger ones as strings, floats with a decimal point (3.0), inf, -inf and nan as strings, and every date or time as its text. The typed form writes each value as {"type", "value"} in the toml-test format, which keeps all of that exactly and converts back to the same TOML data. JSON to TOML reads JSON exactly (number text is kept, duplicate keys are refused), writes objects as tables and arrays of objects as arrays of tables, and cannot express null, so it refuses it or leaves it out as you choose. Comments are dropped and key order is kept, except that TOML needs plain values before sub-tables. It does not validate a schema, format a document in place or keep comments.
How this is checked
5 reference checks passed These 5 cases were run when this page was built, on 20 October 2026, and all reproduce within the stated tolerance. The same cases are part of the automated tests that run on every change to Toolmoz. Engine version 1.
See the checks and where each expected answer comes from
Case 1
- Inputs
- Direction toml-to-jsonJSON form plainJSON indent compactInput 3.14159 = "pi" [dog."tater.man"] type.name = "pug"
- Expected, and what Toolmoz gave
- text expected {"3":{"14159":"pi"},"dog":{"tater.man":{"type":{"name":"pug"}}}} , Toolmoz {"3":{"14159":"pi"},"dog":{"tater.man":{"type":{"name":"pug"}}}} Keys expected 6, Toolmoz 6Tables expected 4, Toolmoz 4
- Where the expected answer comes from
- TOML 1.0.0 specification, Keys and Table sections: 3.14159 = "pi" is a two-part dotted key and maps to { "3": { "14159": "pi" } }; [dog."tater.man"] with type.name = "pug" maps to { "dog": { "tater.man": { "type": { "name": "pug" } } } }. Keys counted by hand: 3, 14159, dog, tater.man, type, name
- Allowed difference
- exact
Case 2
- Inputs
- Direction toml-to-jsonJSON form typedJSON indent compactInput hex1 = 0xDEADBEEF oct2 = 0o755 bin1 = 0b11010110 int7 = 53_49_221 int4 = -17
- Expected, and what Toolmoz gave
- text expected {"hex1":{"type":"integer","value":"3735928559"},"oct2":{"type":"integer","value":"493"},"bin1":{"type":"integer","value":"214"},"int7":{"type":"integer","value":"5349221"},"int4":{"type":"integer","value":"-17"}} , Toolmoz {"hex1":{"type":"integer","value":"3735928559"},"oct2":{"type":"integer","value":"493"},"bin1":{"type":"integer","value":"214"},"int7":{"type":"integer","value":"5349221"},"int4":{"type":"integer","value":"-17"}} Integers expected 5, Toolmoz 5
- Where the expected answer comes from
- Specification Integer section values worked by hand: 0xDEADBEEF = 13·16^7 + 14·16^6 + 10·16^5 + 13·16^4 + 11·16^3 + 14·16^2 + 14·16 + 15 = 3735928559; 0o755 = 7·64 + 5·8 + 5 = 493; 0b11010110 = 128 + 64 + 16 + 4 + 2 = 214; 53_49_221 is 5349221 with underscores removed
- Allowed difference
- exact
Case 3
- Inputs
- Direction toml-to-jsonJSON form plainJSON indent compactInput flt5 = 1e06 flt6 = -2E-2 flt7 = 6.626e-34 sf1 = +inf sf4 = nan
- Expected, and what Toolmoz gave
- text expected {"flt5":1000000.0,"flt6":-0.02,"flt7":6.626e-34,"sf1":"inf","sf4":"nan"} , Toolmoz {"flt5":1000000.0,"flt6":-0.02,"flt7":6.626e-34,"sf1":"inf","sf4":"nan"} Floats expected 5, Toolmoz 5
- Where the expected answer comes from
- Specification Float section: 1e06 is 1 × 10^6 = 1000000, -2E-2 is -0.02, 6.626e-34 is as written; inf and nan have no JSON number form and are written as the strings inf and nan
- Allowed difference
- exact
Case 4
- Inputs
- Direction toml-to-jsonJSON form plainJSON indent compactInput a = 9007199254740991 b = 9007199254740993
- Expected, and what Toolmoz gave
- text expected {"a":9007199254740991,"b":"9007199254740993"} , Toolmoz {"a":9007199254740991,"b":"9007199254740993"} Integers written as strings expected 1, Toolmoz 1
- Where the expected answer comes from
- 2^53 = 9007199254740992, so the largest integer a double holds exactly is 2^53 - 1 = 9007199254740991 (ECMAScript Number.MAX_SAFE_INTEGER); 9007199254740993 is 2^53 + 1, not representable, so it is written as a string
- Allowed difference
- exact
Case 5
- Inputs
- Direction json-to-tomlJSON form plainNull values (JSON to TOML) errorInput {"title":"Toolmoz","owner":{"name":"Ann"},"ports":[80,443],"servers":[{"name":"a"},{"name":"b"}]}
- Expected, and what Toolmoz gave
- text expected title = "Toolmoz" ports = [80, 443] [owner] name = "Ann" [[servers]] name = "a" [[servers]] name = "b" , Toolmoz title = "Toolmoz" ports = [80, 443] [owner] name = "Ann" [[servers]] name = "a" [[servers]] name = "b" Keys expected 7, Toolmoz 7Tables expected 3, Toolmoz 3Integers expected 2, Toolmoz 2
- Where the expected answer comes from
- Written by hand from TOML 1.0.0 rules: an object is a [table], an array of objects is repeated [[servers]] headers, and plain values come before the sub-tables; keys counted by hand: title, owner, name, ports, servers, name, name
- Allowed difference
- exact
What this shows: the engine reproduces independently worked values for these cases. It does not prove every possible input is right. To test an answer you were given, see how to check a number; to see what is and is not checked across Toolmoz, see the accuracy ledger.
See a worked example
Worked example
A fixed demonstration, separate from the values you enter above.
- Direction
- TOML to JSON
- JSON form
- Plain JSON (dates become strings)
- Input
# A small project file title = "Toolmoz" version = 1.0 released = 2026-10-18 tags = ["tools", "private"] [owner] name = "Ann Example" born = 1990-04-12T07:30:00Z [database] ports = [8000, 8001] connection = { max = 5000, enabled = true } [[servers]] name = "alpha" ip = "10.0.0.1" [[servers]] name = "beta" ip = "10.0.0.2"- JSON indent
- 2 spaces
Example result
- Keys
- 17
- Tables
- 5
- Arrays
- 3
- Strings
- 8
- Integers
- 3
- Floats
- 1
- Booleans
- 1
- Dates and times
- 2
- Maximum nesting depth
- 3
- Integers written as strings
- 0
- Characters out
- 464
Plain form: dates and times are written as strings, so a date and a string with the same characters look alike. Choose the typed form to keep every TOML type. Comments are dropped, key order is kept, and floats keep a decimal point (3.0, not 3).