Command Palette

Search for a command to run...

JSON to TOML: Convert Config Files the Right Way

JSON to TOML: Convert Config Files the Right Way

T
Toolz Team
|Sep 13, 2026|17 min letto

Parte della raccolta Strumenti per i dati

Convertitore da JSON a TOML

Converti JSON in TOML 1.0. gli oggetti diventano tabelle, gli array di oggetti diventano array di tabelle e tutto viene reso in linea dove TOML se lo aspetta.

Usa Convertitore da JSON a TOML

The first time TOML bit me, it was not the syntax. It was the ordering. I had a JSON settings object from an old Node service, I wanted it as a config.toml for a Rust rewrite, and I did what everyone does the first time: I hand-typed the tables. Ten minutes later the parser was throwing an error I did not understand, pointing at a line that looked perfectly fine. The problem was three keys sitting below a [table] header that belonged above it. TOML has a rule that JSON does not, and once you trip on it you never forget it.

I build toolz.dev, and I have shipped a long shelf of format converters there, so I wrote the JSON to TOML converter to remove that whole category of mistake. You paste JSON, you get TOML that re-parses to the same data, and the ordering is handled for you. This guide is the thing I wish I had read that afternoon: what TOML is, where JSON and TOML disagree, and how to convert between them without losing anything you cared about.

TL;DR: TOML is a typed configuration format used by Cargo, Poetry, Hugo and a lot of Rust and Go tooling. Converting JSON to TOML is mostly mechanical, but three things need judgement: table ordering (keys before sub-tables, always), how you write arrays of objects (arrays of tables versus inline tables), and what happens to JSON null, which TOML has no way to express. The JSON to TOML converter makes all three explicit and runs entirely in your browser.

What is TOML, and why would I convert JSON into it?

TOML stands for Tom's Obvious, Minimal Language. It reads like an old INI file, but unlike INI it has a real specification with typed values, first-class dates, and a defined grammar. That specification is the reason it won: a config format a person can read at a glance, that a machine parses the same way every time, with no ambiguity about whether port = 8080 is a string or a number. It is a number, because TOML says so.

You reach for JSON to TOML conversion when a machine gave you JSON and a tool wants TOML. That happens more than you would think. An API returns a settings blob as JSON and you need it in pyproject.toml. You have an old config.json and you are moving the project to a stack that reads config.toml. You generated some data programmatically, it came out as JSON because that is what JSON.stringify produces, and the consumer is Cargo or Hugo or a Go service using a TOML library. In every case the data is identical. Only the serialization differs.

The reverse direction exists too, but it is a different job. If you are going the other way, the JSON formatter is worth having open to sanity-check the JSON first, and the JSON to YAML converter covers the other common config format. This guide is about JSON going into TOML.

How does the converter map JSON onto TOML?

There are only a handful of shapes in JSON, and each one has a home in TOML. Understanding the mapping is most of understanding the tool.

A JSON object becomes a TOML table. The top-level object is the root table, which is why the converter insists the input be an object. Nested objects become [table] headers with a dotted path, so { "database": { "pool": { "max": 10 } } } becomes a [database.pool] section with max = 10 inside it.

A JSON array of objects becomes a TOML array of tables, written with the double-bracket [[name]] header, one block per element. This is the idiomatic TOML pattern for a list of records: a list of servers, a list of dependencies, a list of build targets. Each element gets its own [[servers]] block.

Every scalar maps directly. A JSON string becomes a TOML basic string in double quotes, with control characters escaped. A JSON number becomes a TOML integer if it is a whole number and a float otherwise. A JSON boolean becomes true or false. These are the easy cases, and the converter never gets them wrong.

A JSON array of scalars becomes a TOML inline array: ["admin", "editor"] stays ["admin", "editor"]. Mixed arrays and nested arrays are also written inline, because that is the only place they fit.

Why does key ordering matter so much in TOML?

This is the rule that catches everyone, so it is worth stating plainly. In TOML, within any table, all of that table's own key/value pairs must appear before any of its sub-table headers. If you write a [server] header, then some keys, then another key that belongs to the root table, the parser reads that stray key as part of [server] instead. Best case it lands in the wrong place; worst case the file fails to parse.

JSON has no such rule. In JSON, key order is not even significant, and objects and scalars intermix freely inside the same braces. So a naive JSON-to-TOML conversion that walks the object in insertion order and emits each key as it goes will produce broken TOML the moment a scalar follows a nested object.

The converter solves this by making two passes over every table. First it emits all the simple keys, the scalars and inline arrays. Only then does it emit the sub-table and array-of-tables headers, recursing into each. Your key order is preserved within each group, which is what you want, but the required rearrangement between the two groups happens automatically. You never have to think about it, and you never get the error I got.

When should arrays of objects be tables versus inline?

Here is the one genuine choice. An array of objects can be written two ways in TOML, and both are valid.

The first is an array of tables, the double-bracket form. It is verbose and readable, one block per record, and it is what most TOML in the wild looks like. If you have seen a Cargo.toml with several [[bin]] entries, you have seen this.

[[servers]]
name = "web"
ip = "10.0.0.1"

[[servers]]
name = "api"
ip = "10.0.0.2"

The second is an inline table inside a normal array, which packs each object onto one line.

servers = [
  { name = "web", ip = "10.0.0.1" },
  { name = "api", ip = "10.0.0.2" },
]

Both round-trip to the same data. Which one you want depends on the target and on taste. Arrays of tables read better for records a human will edit, and they are the convention for most tooling config. Inline tables are more compact and closer to the shape of the original JSON, which some people prefer when the list is short or the objects are tiny. The converter defaults to arrays of tables and gives you a toggle to switch. If you are unsure, leave it on the default: it is what a TOML file usually looks like.

What happens to JSON null in TOML?

TOML has no null. There is no keyword, no empty value, nothing. This is a deliberate design decision by the format, and it is the one place where JSON to TOML is genuinely lossy.

So the converter has to make a choice, and it lets you make it. By default, a key whose value is null is dropped, and the tool lists the dropped keys in a note under the output so nothing disappears silently. If you would rather keep the key, you can switch to writing null as an empty string, which preserves the key at the cost of changing its type. Neither is perfect, because there is no perfect answer. What matters is that the choice is visible rather than buried.

Nulls inside arrays are always dropped, with a warning, because a TOML array cannot contain null at all. If your JSON has [1, null, 3], the TOML will be [1, 3] and the tool will tell you it removed one. If those nulls carry meaning, that is a signal to reshape the data before converting rather than after.

Why did my number lose its decimal, or gain one?

This one surprises people who care about types. JSON does not distinguish 5 from 5.0. Both parse to the same IEEE 754 double, and by the time JSON.parse is done there is no trace of the trailing zero. So when the converter sees the number 5, it has no way to know you meant a float, and since 5 is a whole number it writes a TOML integer.

TOML, on the other hand, does distinguish integers from floats, and some tools care about the difference. If you need a value typed as a float, the fix is to give it a fractional part in the source, 5.1 or 5.0 written in a way that survives, or to edit the single value after conversion. It is a one-character change and it is rare, but it is worth knowing why it happens rather than assuming the converter is wrong. It is not wrong. JSON simply threw the information away before the converter ever saw it.

The reverse case shows up with very large or very small numbers, where JavaScript's String() produces exponent notation like 1e+21. TOML accepts that as a float, so it converts fine, but the shape of the number may look different from what you typed. Again, the value is identical; only the rendering changed.

How do bare and quoted keys work?

TOML lets a key be written bare if it is made only of letters, digits, underscores and dashes. Anything else, a key with a dot, a space, a slash, a Unicode character, has to be quoted. The converter checks each key and quotes only the ones that need it, so user-name stays bare and "user.name" gets quotes to stop the dot being read as a table path. You do not have to think about this, but if you see quotes around a key in the output, that is why: the key contained a character that would otherwise change its meaning.

A worked example

Here is the sample the tool loads, so you can see every rule at once. The JSON:

{
  "title": "Toolz config",
  "version": 2,
  "enabled": true,
  "owner": { "name": "Liton", "roles": ["admin", "editor"] },
  "database": { "host": "localhost", "port": 5432, "pool": { "min": 2, "max": 10 } },
  "servers": [
    { "name": "web", "ip": "10.0.0.1" },
    { "name": "api", "ip": "10.0.0.2" }
  ]
}

becomes TOML where the root scalars come first, the nested objects become dotted tables in order, and the array of servers becomes two [[servers]] blocks:

title = "Toolz config"
version = 2
enabled = true

[owner]
name = "Liton"
roles = ["admin", "editor"]

[database]
host = "localhost"
port = 5432

[database.pool]
min = 2
max = 10

[[servers]]
name = "web"
ip = "10.0.0.1"

[[servers]]
name = "api"
ip = "10.0.0.2"

Notice that title, version and enabled are written before any header, roles stays an inline array because it is an array of strings, and [database.pool] sits under [database] as a dotted path. Every rule in this guide is visible in nine lines of output.

Which tool for which conversion?

TOML is one format in a family, and the right tool depends on where you are starting and ending. Here is how I think about it.

You have You want Use
JSON TOML config JSON to TOML
JSON YAML config JSON to YAML
YAML JSON YAML to JSON
JSON XML JSON to XML
Messy JSON Readable JSON JSON formatter

The pattern is that config formats are interchangeable views of the same data, and the converter you want is named for the direction you are going. TOML, YAML and JSON all express nested key/value data; the difference is which one your target tool reads.

Is it safe to convert a config file online?

Config files are exactly the kind of thing you should be careful about pasting into a website, because they often contain connection strings, tokens, and other secrets. The JSON to TOML converter runs entirely in your browser. The JSON you paste is parsed in memory on your device, the TOML is produced there, and nothing is sent to a server, written to a log, or stored. You can watch this yourself: open your network tab, run a conversion, and see that no request goes out. It also keeps working with no connection once the page has loaded, which is the practical proof that the work is local. If you care about where your data goes, and with a config file you should, this is the property that matters. It is the same principle behind every tool on the site, and the reason I wrote about it at length in the note on data privacy in online tools.

Where this fits in a real workflow

Format conversion is rarely the whole task. It is a step. You pull a settings object out of an API, you convert it, you drop it into a project. The value of a client-side converter is that it slots into that flow without friction: no upload, no account, no waiting on a server, no wondering whether your secrets are now in someone's logs. That is the same reason I keep the whole toolz.dev set client-side, and it is a theme I come back to in the developer productivity tools write-up, because the tools you reach for twenty times a day are the ones where a two-second round trip and a privacy question add up.

TOML earned its place in that flow by being boring in the best way. It parses the same everywhere, it reads well, and its one sharp edge, the ordering rule, is exactly the sort of thing a converter should file down for you. Paste your JSON, pick how you want arrays and nulls handled, and copy TOML that just works.

Frequently asked questions

How do I convert JSON to TOML?

Paste your JSON object into the converter and click Convert. The tool serialises objects to TOML tables, arrays of objects to arrays of tables, and every other value inline, then gives you standard TOML to copy. The top-level JSON must be an object, because a TOML document is always a table.

What is TOML used for?

TOML is a configuration file format designed to be easy to read and unambiguous to parse. It is the config format for Rust's Cargo (Cargo.toml), Python packaging (pyproject.toml), Hugo, and many Go and Rust tools. People convert JSON to TOML to hand a machine-generated config to a tool that expects TOML.

What happens to JSON null values in TOML?

TOML has no null type, so a JSON null cannot be represented directly. By default this converter drops null keys and adds a note listing them; you can switch to writing them as empty strings instead. Nulls inside arrays are always dropped, because a TOML array cannot contain null.

What is the difference between an array of tables and an inline table?

An array of tables uses repeated double-bracket headers, one block per record, and is the idiomatic TOML way to write a list of objects such as a list of servers or dependencies. An inline table packs an object onto one line as a set of key equals value pairs in braces. This tool defaults to arrays of tables but lets you choose inline instead.

Why did my JSON number 5.0 become 5 in TOML?

JSON does not preserve the difference between 5 and 5.0, so parsing reads both as the number 5. Since 5 is a whole number, the converter writes it as a TOML integer. If you need it typed as a float, add a fractional part in the source or edit the single value after conversion.

Does the converter keep my key order?

Yes. Keys are emitted in the order they appear in the JSON, with one required rearrangement: within each table, plain keys are written before any sub-table or array-of-tables headers. That is a TOML syntax rule, not a reordering choice, and without it the file would not parse.

Is my JSON uploaded to a server?

No. The entire conversion happens in your browser using plain JavaScript. Your JSON, including any secrets or credentials in a config file, is never transmitted, logged, or stored, and the converter keeps working with no connection once the page has loaded.

Why does it say the top level must be an object?

A TOML document is defined as a table, which means it must start from a set of key/value pairs. A bare JSON array or scalar has no table to map onto. Wrap it in an object first, for example putting your array under a named key, and it will convert.

Comments

0 comments

0/2000 characters

No comments yet. Be the first to share your thoughts!