Developer tools

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.

TOML and JSON converter
Esc to restore

Your inputs

The JSON you get from TOML, or the JSON you paste for TOML. Typed JSON wraps every value as {"type": "integer", "value": "42"} so nothing is lost.

One TOML 1.0.0 document, or one JSON value whose top level is an object. Up to 1 MB. Nothing is uploaded.

TOML has no null.

Results update as you type. Larger files run when you press Update result.

Your result

Your result will appear here.

More actions

Your inputs stay in this browser. Nothing is uploaded or saved.

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
  1. 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
  2. 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
  3. 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
  4. 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
  5. 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).