TOON Format Explained: Where It Saves Tokens and Where It Does Not

By Wesley · · 8 min read

TOON (Token-Oriented Object Notation) is a text format for the same data model as JSON: objects, arrays, strings, numbers, booleans and null. It exists for one purpose, which is putting structured data into an LLM prompt with fewer tokens. It is not a replacement for JSON in APIs or storage. Whether it helps depends almost entirely on the shape of your data, so this article shows both the good case and the bad one.

The syntax in five rules

1. Objects use indentation instead of braces, and keys and most string values are unquoted.

JSON
{
  "player": {
    "name": "Shadow Knight",
    "level": 42,
    "active": true
  }
}
TOON
player:
  name: Shadow Knight
  level: 42
  active: true

2. Arrays of primitives go on one line, with the length declared in brackets.

tags[3]: admin,ops,dev

3. Arrays of uniform objects become a table. The header states the length and the field names once; each row then lists only values. This is where nearly all of the savings come from.

users[3]{id,name,role}:
  1,Alice,admin
  2,Bob,user
  3,Cara,user

4. Arrays that are not uniform fall back to a list, one - item per element, similar to YAML.

items[3]:
  - id: 1
    name: A
  - id: 2
    tags[1]: x
  - plain string

5. Strings are quoted only when they would be misread. The encoder adds quotes when a value could be taken for another type or would break the line structure:

ValueEncoded asReason
hello worldhello worldUnambiguous, inner spaces are fine
the string "true""true"Would decode as a boolean
the string "42" or "007""42", "007"Would decode as a number
a,b"a,b"Contains the delimiter
x: y"x: y"Contains a colon
empty string""Otherwise invisible
a value with leading or trailing spaces" pad "Whitespace would be trimmed

Measured: flat data versus nested data

We encoded two datasets with the reference TypeScript library (@toon-format/toon 2.1) and counted characters. Characters are not tokens, but for ASCII-heavy data they move together, and character counts can be reproduced without choosing a tokenizer.

Flat, uniform records
JSON, 2-space indent
22,762
JSON, minified
14,354
TOON
7,776 (−46% vs minified)
characters
200 flat user records: id, name, email, active. Every record has the same four primitive fields.
Records with nested fields
JSON, 2-space indent
50,122
JSON, minified
28,114
TOON
31,114 (+11% vs minified)
characters
The same 200 records with a nested address object and a roles array added to each.

The second result surprises people. Adding one nested object to each record makes the array ineligible for the table form, so the encoder falls back to the list form and repeats every key on its own indented line. The output is still smaller than pretty-printed JSON, but larger than minified JSON.

The TOON project's own token benchmarks (GPT o200k_base tokenizer) show the same pattern:

DatasetTOON vs. formatted JSONTOON vs. minified JSON
Uniform employee records (100% tabular)−60.7%−36.8%
E-commerce orders, nested (33% tabular)−33.1%+5.5%
Semi-uniform event logs (50% tabular)−15.0%+19.9%
Deeply nested configuration (0% tabular)−31.3%+11.9%

Source: the benchmarks section of the TOON repository. Negative numbers mean TOON used fewer tokens.

A rule of thumb

  • Use TOON when the bulk of the payload is arrays of objects that share the same primitive fields: database rows, search results, product lists, time series, log records with a fixed schema.
  • Use minified JSON for deeply nested or irregular structures such as configuration trees, or when the arrays hold objects with differing keys.
  • Use CSV if the data is one flat table and nothing else. CSV is slightly smaller still; TOON spends a few percent on the length and field declarations.
  • Flatten first if you control the shape. Turning address.city into a top-level city column before encoding restores the table form and the savings with it.
Compare against the right baseline
Many "TOON saves 50%" claims compare against pretty-printed JSON. If you already send minified JSON, measure against that. On well-suited data the gain is real but closer to 35–45%, and on poorly suited data it is negative.

Using TOON in prompts

  • Show the format, do not explain it. Models read TOON without instructions when the data is placed in a fenced code block labelled toon.
  • The header is a guardrail. [3] tells the model how many rows to expect and {id,name,role} names the columns. That structure helps with questions like "how many users are admins" and makes truncated input detectable.
  • For output, give the header. When you want the model to answer in TOON, show the header line you expect and let it fill in rows. Then decode with strict validation; see decoding TOON back to JSON.
  • Measure latency too. Fewer tokens usually means faster responses, but some local model setups handle compact JSON faster. Test on your own stack.

Encoding in code

TypeScript
import { encode } from '@toon-format/toon';

const prompt = [
  'Answer using the data below.',
  '```toon',
  encode({ users }),
  '```',
].join('\n');

The conversion is lossless: decoding the result gives back the same values. Implementations exist for Python, Go, Rust, Java and other languages, all following one written specification.

See it on your own data

JSON to TOON ConverterPaste JSON, get TOON, and compare character and estimated token counts side by side.