JSON to TOON Converter
Convert JSON to TOON to use fewer tokens in LLM prompts and API payloads.
TOON writes an array of uniform objects as a header plus rows, so each field name is spelled once for the whole table instead of once per record. That single change is where the savings come from, and it also explains exactly which data shapes get smaller and which get nothing at all.
Where the savings actually come from
Take the sample loaded into the converter above: three records, four fields each. As minified JSON it is 159 characters. As pipe-delimited TOON it is 87 — a 45% reduction. Against the same data pretty-printed with two-space indentation, which is how JSON usually reaches a prompt, it is 250 characters against 87, or a 65% reduction.
The arithmetic is worth internalising because it predicts everything else on this page. For every field of every record, JSON spends two quote characters, a colon, a comma, and the full text of the key. TOON spends one delimiter, and writes the key text once in the header. So the saving is roughly the per-row cost of the key names and their punctuation, multiplied by the number of rows — which is why it grows with both row count and field count.
It also shrinks as values get longer, because values pass through byte for byte. A table of short integers and enum values compresses dramatically; a table where every row carries a 200-word description barely moves, since the scaffolding you removed was already a rounding error next to the prose. And tokens are not characters: delimiters, newlines, and digit groupings all tokenise in their own way, so measure with the tokenizer your model actually uses before quoting a percentage to anyone. The header [3]{id|name|role|active}| also does something a character count will not show — it states the record count and the field names before the first row, so the structure is declared rather than inferred.
Uniformity is a hard gate, not a preference
The tabular encoding only applies when every element of an array is a non-null object carrying exactly the same set of keys. The check is all-or-nothing: [{"a":1,"b":2},{"a":3}] has one element missing b, so the array is not uniform and the converter emits it as ordinary JSON. You get zero savings and no error, which is the single most common reason someone converts a large file and sees almost no change in size.
Optional fields are the usual culprit — the record where middle_name was omitted rather than set to null. Normalise before converting: fill every missing key with an explicit null so the key sets match. It costs four characters per gap and unlocks the tabular form for the entire array.
Two related behaviours are more forgiving than you might expect. Key order does not have to match, only the key set: [{"a":1,"b":2},{"b":4,"a":3}] is uniform, and because each row is built by looking up the header keys rather than reading positionally, the values stay in the right columns. And an array of scalars such as [1,2,3] is passed through as JSON — nothing is lost, but nothing is gained either, because there are no repeated key names to eliminate.
Pick the delimiter your values do not contain
Three modes are available. Pipe is the default and produces [3]{id|name|role|active}| with pipe-separated rows. Comma mode produces [3]{id,name,role,active}, and reads like CSV with a header. Tab or standard mode is the YAML-flavoured one: objects become key: value and arrays get a colon suffix, as in items[2]{id,qty}: followed by comma-separated rows.
This choice matters more than it looks, because values are written out verbatim — there is no quoting and no escape character anywhere in the format. A value containing the active delimiter simply adds a field. In comma mode, [{"id":1,"note":"a,b"},{"id":2,"note":"c"}] produces the row 1,a,b under a two-column header: three values where two were promised, and the row is now unrecoverable. The same data in pipe mode is 1|a,b and survives intact.
So: pipe for anything containing prose, since English is full of commas and short of pipes. Comma for numeric or coded data you might also want to paste into a spreadsheet. And check for newlines first regardless of mode — the format is line-oriented, so a value containing a line break splits one record into two rows that no parser can reassemble.
What the encoder flattens on the way out
A row is a line of scalars, so anything that is not a scalar has to be coerced into one. An array whose objects contain a nested object still passes the uniformity check — the key sets match — and then that column is stringified: [{"id":1,"meta":{"x":1}}] becomes a row reading 1|[object Object]. The data is gone, not encoded. A nested array degrades more gently but still loses its type, with ["a","b"] becoming the text a,b.
The fix is to flatten before converting rather than after: hoist meta.x to a top-level meta_x column, or serialise the sub-object to a string yourself so you control the representation. One level of nesting is handled natively — a uniform array sitting under an object key gets its own inline header, so {"name":"Alice","items":[...]} emits name: Alice followed by items[2]{id,qty}: and its rows.
The other thing dropped on the way out is quoting, and with it the string-versus-scalar distinction. The JSON string "true" and the boolean true both emit the four characters true, and the number 7 and the string "7" are equally indistinguishable. Nothing in the TOON output records which one you started with, so any value whose textual form matters — a zero-padded identifier, a version number, a postcode — should be reviewed before you rely on a round trip.
Data shapes where JSON is still the right answer
Four cases give back little or nothing. Arrays of scalars have no repeated keys to remove. A single deeply nested object still spells out every key exactly once in either format, so you save the braces and quotes and little else. Short arrays cannot amortise the header, which costs about one row's worth of key text on its own. And ragged or polymorphic arrays — the event log where each entry type has different fields — fail the uniformity check by construction, and are usually better served by grouping records by type and converting each group separately.
There is also a hard boundary worth respecting: TOON is a format for the prompt, not for the system. Provider APIs for tool calls and structured output are specified in terms of JSON Schema, so however you send data to the model, what comes back still has to be JSON. Storage, logs, and anything with a schema registry should stay JSON too, since TOON has no validator ecosystem to check a document against a contract.
The workable pattern is to keep JSON as the stored form and convert at prompt-build time, keeping the original alongside the request so that anything the model returns can be reconciled against it. When the model replies with TOON of its own — because you asked it to, or because it followed your example — the TOON to JSON converter covers what to check on the way back.
Related tools
Try these tools that work well with this one
TOON to JSON Converter
Convert TOON back to standard JSON
CSV to JSON Converter
Convert CSV data to JSON
JSON to CSV Converter
Convert JSON arrays of objects to CSV
JSON to YAML Converter
Convert JSON to YAML
YAML to JSON Converter
Convert YAML to JSON
CSV to XML Converter
Convert CSV text to XML
Related guides
Tutorials and guides to get more from this tool
Introducing TOON: The Token-Oriented Object Notation
Meet TOON, the new data format designed for the AI era. Save 50% on LLM tokens and optimize your structured data exchange.
TOON vs JSON: A Benchmark of Token Savings
We compared TOON against JSON across various datasets. The results? Up to 65% reduction in token usage.
The Ultimate Guide to Data Serialization: JSON, YAML, XML, and TOON
From legacy XML to modern JSON and TOON, explore the evolution of data serialization formats and when to use them.
ThenCatch is a free developer toolkit. Learn more about us.