JSON to TOML Converter

Paste the JSON, pick how nested objects should be written, and read the TOML back with every table header, dotted key, and [[array entry]] in the order a parser expects. The panel on the right lists what TOML refused to take, starting with nulls.

Start from

JSON

0 B

Waiting for JSON.

TOML

0 B
Tables
0
[[Array]] entries
0
Keys
0
Nulls
0
Quoted keys
0
Dates
0

Convert JSON to TOML without hand-typing every table header

Most JSON to TOML jobs start the same way. A build script, an API, or a code generator hands you a JSON object, and the file you need to ship is pyproject.toml, Cargo.toml, netlify.toml, or a Hugo site config. Typing the headers by hand goes wrong at the third level of nesting, and the first mistake a TOML parser reports is usually a table defined twice. This page does the walk for you. Paste the JSON, and the output pane fills with a document where every plain value sits above the sub-tables of its parent, which is the order TOML requires.

The conversion runs in your browser and nothing leaves the tab. The parser is the browser's own JSON.parse, so a stray trailing comma or an unquoted key stops the page with a line and column. Click "Go to the line" and the cursor lands on the problem in the JSON pane.

One nested object, three ways to write it

TOML gives you more than one spelling for a nested object, and the file you are targeting usually has a house style. Take this fragment:

{ "owner": { "name": "Wajahat Qasim", "role": "maintainer" } }

With Table headers selected, the converter writes a block, which is how Cargo.toml spells [package] and how pyproject spells [project]:

[owner]name = "Wajahat Qasim"
role = "maintainer"

Dotted keys keep the pairs at the parent level. Hugo configs and small [tool.*] sections read well this way, since a two-key object does not earn its own header:

owner.name = "Wajahat Qasim"
owner.role = "maintainer"

Inline tables put the object on one line. Cargo dependency specs are the classic case, serde = { version = "1.0", features = ["derive"] }. The converter only inlines objects whose values are all plain scalars and whose key count stays under the limit you set. Anything deeper falls back to a header, because a TOML inline table has to fit on a single line and cannot be extended later in the file.

Whichever mode you pick, an object with sub-objects of its own always becomes a header. The dotted and inline forms are shortcuts for flat leaves, not a general replacement for tables.

Arrays of objects become [[double bracket]] tables

A JSON array where every element is an object maps to TOML's array of tables. Netlify redirects are the pattern most people recognise:

[[redirects]]from = "/blog/*"
to = "https://toolexe.com/articles/:splat"
status = 301
[[redirects]]from = "/*"
to = "/index.html"
status = 200

Nesting inside those entries works the way the TOML spec describes. A sub-object under a [[fruits]] entry is written as [fruits.physical] and attaches to the most recent entry. A nested array of objects becomes [[fruits.varieties]]. The "Headers written" list on the right shows every header in the order the file uses them, with entry counts, so you check the shape before you scroll the output.

If an array mixes objects with strings or numbers, or one element is a nested array, the whole array is written inline with inline tables for the objects. TOML 1.0 allows mixed-type arrays. TOML 0.5 readers reject them, so an older parser in your toolchain is a reason to reshape the JSON first.

Switch "Arrays of objects" to the inline setting when the objects are tiny and there are many of them. A list of forty one-line { name = "...", weight = 10 } tables scans faster than forty [[menu.main]] blocks.

What TOML refuses to take from JSON

JSON is a superset of what TOML expresses in a few places, and the converter has to make a call each time. The "Worth checking" panel names every one of them for the document you pasted.

Strings, escapes, and the date guess

Plain strings go out in double quotes with the usual escapes for quotes, backslashes, tabs, and control characters. Two toggles change that for specific shapes:

Date detection is the toggle to watch. A string matching RFC 3339, such as 2026-09-11T14:05:00Z, a bare date 2026-04-18, or a bare time 14:05:00, goes out unquoted, and a TOML reader returns a real datetime instead of text. That is usually what a config wants. Turn the toggle off when the field is a version label or a string ID that only looks like a date, because the type change follows the value into your application.

Files people paste here

pyproject.toml from a setup.py migration script or from pip inspect. Use table headers, since [project], [build-system], and [tool.ruff] are the shape every Python tool reads. Cargo.toml from a dependency audit, where inline tables keep the dependency block compact. netlify.toml and Hugo's hugo.toml, where arrays of tables carry redirects, headers, and menu items. And plain application config, where JSON was the storage format and TOML is what the ops team asked for because comments are allowed.

One thing the page cannot do is invent the comments. TOML's main advantage over JSON is a # line above a setting explaining why the value is what it is. Add those after you paste the output into the repo.

Where this page stops

The converter handles documents in the low megabytes comfortably. Past that, the live re-conversion on every keystroke starts to lag, and a command line tool is the better fit. It writes TOML 1.0, so mixed arrays and multi-line inline values assume a modern parser. Key order follows the JSON unless you sort, and the sort is plain code-point order, which puts uppercase before lowercase. Comments in the input are not supported because JSON has none. Blank lines between tables are fixed at one. If you need the reverse trip, the TOML to JSON converter parses TOML back into an object, and the TOML validator checks a file you edited by hand.

JSON to TOML questions

Why does the output put all the plain keys before the first [table] header?

TOML reads a file top to bottom, and a key written after a header belongs to that table. Every plain value in a table has to appear before the first sub-table header, otherwise the value is assigned to the wrong table or the parser reports a duplicate. The converter reorders the pairs so the file parses, even when the JSON listed a nested object first.

My JSON has null values. What happens to them?

TOML has no null type, so there is no exact match. By default the key is left out, which most readers treat the same as unset. Pick the comment option to leave a marker in the file, or the empty string option if your schema requires the key. The Worth checking panel lists every path where a null was found so you know what to look for.

Can I convert a JSON array at the top level?

Not directly. A TOML document is a table, so the outermost value has to be an object. The page offers to wrap the array under an items key, which turns each element into a [[items]] entry. Rename the key in the output to match your file.

Why did a number like 3.0 turn into 3?

JSON has one number type and the browser reads 3.0 as the integer 3 before the converter sees it. TOML keeps integers and floats separate, so the output says 3. If a strict reader expects a float, change the value to 3.0 by hand after copying, or keep the field as a string in the JSON.

Is the converted TOML valid for Cargo.toml and pyproject.toml?

The syntax is valid TOML 1.0, which both cargo and pip read. Whether the content is valid depends on the keys, since cargo rejects unknown fields and pyproject has a fixed schema. The converter does not know those schemas. Run cargo check or a pyproject validator after pasting.

Does anything get uploaded?

No. Parsing and conversion run in your browser with the built-in JSON parser and a small writer script. Nothing is sent to a server, so credentials and internal hostnames in the JSON stay on your machine.