TOON in Python and JavaScript: A Hands-On SDK Guide
Install, encode, decode, and validate TOON in Python and JavaScript/TypeScript with copy-paste examples and a JSON-to-TOON migration checklist.
TOON has official implementations in both TypeScript (the reference implementation by Johann Schopplich, MIT-licensed) and Python (still in beta). This guide walks through install, encode, decode, and a full round-trip in both ecosystems using @toon-format/toon 4.1.1 (TOON spec 4.1), then gives you a JSON-to-TOON migration checklist.
Why add a TOON dependency at all?
Before writing any code it is worth knowing what you are optimizing for. The official TOON benchmark (v4.1 run: 5,856 LLM calls across four models) found that TOON uses 42.6% fewer tokens than JSON while matching JSON on retrieval accuracy (72.2% vs 71.4%, within overlapping confidence intervals). On flat, uniform tables (the exact shape you get from a database query or an API list endpoint) savings reach 58.7%.
The savings compound when you pay per token (OpenAI, Anthropic, Google) and your prompt injects large datasets. A pipeline that today costs $1,000/month in input tokens could drop to roughly $600 by swapping the serializer. That is why a one-line install is worth understanding.
One honest caveat: an independent arXiv paper (arXiv 2603.03306) found that TOON's edge shrinks for generation tasks (asking a model to output TOON) because of the upfront "prompt tax" — the instructional tokens needed to describe the format to the model. TOON shines on large, repetitive payloads being fed into the LLM as context, not as output schema.
If you want a no-code path first, try the free JSON to TOON converter — paste JSON, get TOON back instantly, all in-browser. From any other language, POST your JSON to the TOON API and get TOON back.
TOON by language: packages at a glance
| Language | Package | Install | Status |
|---|---|---|---|
| TypeScript / JavaScript | @toon-format/toon | npm i @toon-format/toon | Official reference — MIT |
| Python | toon-python | pip install --pre toon-format | Official, beta (0.9.0b1) — MIT |
| CLI | @toon-format/cli | npx @toon-format/cli input.json --stats | Official — MIT |
| Rust, Java, Go, .NET, Swift, Dart, Julia | community ports | see GitHub org | Official community ports / check spec version |
Always check the toon-format GitHub organisation for the latest list of official and community ports.
How to encode and decode TOON in TypeScript / JavaScript
The TypeScript reference package was authored by Johann Schopplich and released under the MIT licence. Version 4.1.1 (August 2026) implements TOON spec 4.1. Install it from npm:
npm i @toon-format/toonEncode: JSON array of objects to TOON
The package exports encode and decode. Wrap the array in an object so it gets a named header; a bare root array encodes as [3]{id,customer,total,status}: with no key. The output below is real 4.1.1 output:
import { encode, decode } from "@toon-format/toon";
const orders = [
{ id: 1, customer: "Alice", total: 49.99, status: "shipped" },
{ id: 2, customer: "Bob", total: 12.50, status: "pending" },
{ id: 3, customer: "Carol", total: 199.00, status: "delivered" },
];
// Encode JavaScript value → TOON string
const toonString = encode({ orders });
console.log(toonString);
/* Output:
orders[3]{id,customer,total,status}:
1,Alice,49.99,shipped
2,Bob,12.5,pending
3,Carol,199,delivered
*/Notice the header line orders[3]{id,customer,total,status}: — it tells the LLM the array name, item count, and field schema before a single data row appears. Numbers are canonicalized (12.50 becomes 12.5, 199.00 becomes 199), and rows have no spaces after the commas.
Decode: TOON string back to JavaScript
// Decode TOON string → JavaScript value
const restored = decode(toonString);
console.log(restored.orders[0].customer); // "Alice"
console.log(restored.orders[1].total); // 12.5
// Round-trip check
console.log(JSON.stringify(restored) === JSON.stringify({ orders })); // trueThe round-trip is lossless for all primitives JSON supports. If your original data contains binary, encode it as a base64 string before passing to encode().
Encoder and decoder options in v4
The 4.x API is small. These are the options and helpers you will actually use:
indentSize: spaces per level (default 2). It replaced the olderindentoption, which still works but is deprecated.delimiter:","(default),"\t", or"|"for tabular rows and inline arrays.replacer: aJSON.stringify-style(key, value, path)function; returnundefinedto drop a field.rawString(): return it from a replacer to emit a pre-formatted value verbatim.encodeLines(): yields TOON lines one at a time for streaming large outputs.decodeStream()/decodeStreamSync(): turn TOON lines into JSON events without building the full value.strict(decode, defaulttrue): validates array lengths and row counts, and throwsToonDecodeError(since 2.2.0, aSyntaxErrorsubclass withlineandsourcefields).
import { encode, decode, ToonDecodeError } from "@toon-format/toon";
const user = { id: 1, name: "Ada", password: "secret" };
const toon = encode(user, {
delimiter: "|",
replacer: (key, value) => (key === "password" ? undefined : value),
});
try {
decode("users[3]{id,name}:\n 1,Alice\n 2,Bob");
} catch (err) {
if (err instanceof ToonDecodeError) {
console.error(err.line, err.message);
// 3 "Line 3: Expected 3 tabular rows, but got 2"
}
}The v4 encoder also emits keyed tables (flags[3:]{enabled,rollout}:) for objects of same-shape objects and nested field groups (orders[2]{id,customer{name,country},total}:) for uniform nested objects. Key folding was removed in 4.0, so the old keyFolding and expandPaths options do nothing. See the TOON syntax cheat sheet for every form.
Using TOON inside a prompt (Node.js / Next.js example)
import { encode } from "@toon-format/toon";
async function buildPrompt(rows: Record<string, unknown>[]) {
const toon = encode(rows);
return `You are a data analyst. Answer the question using only the data below.
DATA:
${toon}
QUESTION: Which customer has the highest total?`;
}
// On flat uniform arrays, the TOON block is typically up to ~59% smaller
// than JSON.stringify(rows, null, 2).For a full TypeScript integration walkthrough, see the TypeScript install guide.
How to encode and decode TOON in Python
The official Python implementation lives at github.com/toon-format/toon-python. It is in beta: the latest PyPI release is 0.9.0b1, a pre-release, so a plain pip install toon-format still resolves to the older 0.1.0. Install the beta explicitly, or install from GitHub as the README suggests:
pip install --pre toon-format
# or
pip install git+https://github.com/toon-format/toon-python.gitThe README states the library is "working towards spec compliance" and the API may change before 1.0.0. Its options still use the older names (indent, delimiter, lengthMarker), and you should not assume v4 features such as keyed tables, nested field groups, or comments until you have tested them. If you need exact spec 4.1 output today, generate TOON with the TypeScript package or CLI. The output shown below is what a spec-compliant encoder produces:
Encode a list of dicts to TOON
from toon_format import encode, decode
orders = [
{"id": 1, "customer": "Alice", "total": 49.99, "status": "shipped"},
{"id": 2, "customer": "Bob", "total": 12.50, "status": "pending"},
{"id": 3, "customer": "Carol", "total": 199.00, "status": "delivered"},
]
toon_string = encode({"orders": orders})
print(toon_string)
# orders[3]{id,customer,total,status}:
# 1,Alice,49.99,shipped
# 2,Bob,12.5,pending
# 3,Carol,199,deliveredSpec section 2 makes numbers canonical, so the Python float 199.0 is written as 199 and decodes back as an integer. That is why the round-trip check below compares values rather than types.
Decode TOON back to Python
restored = decode(toon_string)
print(restored["orders"][0]["customer"]) # Alice
print(restored["orders"][1]["total"]) # 12.5
# Round-trip assertion (199 == 199.0 in Python)
assert restored == {"orders": orders}Injecting TOON into an LLM prompt (Python / OpenAI SDK example)
from toon_format import encode
import openai
def build_messages(rows: list[dict]) -> list[dict]:
toon = encode({"rows": rows})
return [
{"role": "system", "content": "Answer using only the provided data."},
{"role": "user", "content": f"DATA:\n{toon}\n\nQUESTION: List the shipped orders."},
]
client = openai.OpenAI()
response = client.chat.completions.create(
model="gpt-5.6-luna",
messages=build_messages(orders),
)
print(response.choices[0].message.content)Benchmarks on toonformat.dev/guide/benchmarks show TOON achieves 29.2 accuracy-points per 1,000 tokens vs JSON's 16.6 in the current v4.1 run, about 76% more accuracy per token. For a Python data pipeline injecting thousands of rows per request, the cumulative cost difference is significant.
JSON vs TOON side by side
The same three-order dataset, serialized both ways, makes the token difference concrete:
/* JSON — 195 characters */
[
{"id":1,"customer":"Alice","total":49.99,"status":"shipped"},
{"id":2,"customer":"Bob","total":12.50,"status":"pending"},
{"id":3,"customer":"Carol","total":199.00,"status":"delivered"}
]
/* TOON (encode output, root array) — 99 characters */
[3]{id,customer,total,status}:
1,Alice,49.99,shipped
2,Bob,12.5,pending
3,Carol,199,deliveredOn this toy example TOON is about 49% shorter in characters. On production-scale data the benchmark's e-commerce orders dataset (nested customers and line items) used 32.9% fewer tokens than JSON in the current run. Flat uniform tables such as employee records and time series save about 59-61%.
For a deeper look at when these numbers hold and when they do not, read JSON vs TOON: a full comparison.
JSON-to-TOON migration checklist
Use this list before shipping TOON in a production pipeline. See also the detailed migration guide.
- Identify hot paths. Profile which prompts consume the most tokens. Prioritise those — converting cold paths adds complexity for minimal gain.
- Confirm your data is uniform. TOON's biggest wins come from arrays of objects with consistent keys. Heterogeneous, deeply nested structures save less (event logs: 15% in the current benchmark, and compact JSON can win). If data is purely flat with no nesting, also consider plain CSV.
- Install and pin the package. Use
npm i @toon-format/toonorpip install --pre toon-format. Pin to a specific version in your lockfile. Spec 4.0 was a breaking change (comments, removed key folding), so upgrade decoders before encoders. - Replace the serializer at prompt-build time. Swap your
JSON.stringify(data)(orjson.dumps(data)) call forencode(data)in the one place that builds the LLM context string. - Test the round-trip. Add a unit test asserting
decode(encode(data))deep-equals the original object. Run it in CI on representative fixtures. - Validate LLM output if you generate TOON. If you ask the model to output TOON (not just read it), add a decoding step with error handling. The arXiv study (2603.03306) found generation accuracy is lower than retrieval accuracy — plan for malformed output.
- Measure token counts before and after. Log
usage.prompt_tokensfrom your LLM API response. Confirm the savings match expectations before rolling out broadly. - Update prompt instructions if needed. Most frontier models understand TOON without explanation, but on smaller or specialised models you may need a one-sentence description of the table header syntax. Keep it short — each instruction line is tokens too.
When should you stick with JSON?
TOON is not a universal replacement. JSON still wins when:
- Your data is highly non-uniform — mixed types per row, variable keys, deeply nested documents. TOON saves little here, and the official README says compact JSON often wins. See when not to use TOON.
- You need schema validation or typed generation at scale — consider TONL, which adds type hints and a query API.
- Your payload is small (a handful of objects). The "prompt tax" of describing TOON to the model may exceed the token savings on tiny payloads.
- Constrained decoding is in play — the arXiv paper found constrained-decoding JSON can match TOON efficiency on simple structures.
Understanding the format in detail helps make this call. Start with What is TOON? and the TOON specification if you want to read the grammar before committing.
Frequently Asked Questions
Is there a TOON library for Python?
Yes, but it is still in beta. The official Python implementation lives at github.com/toon-format/toon-python and exposes encode and decode via from toon_format import encode, decode. The beta is PyPI 0.9.0b1 (pip install --pre toon-format); the README also suggests installing from GitHub. It is still working toward full spec compliance, so check v4 features before relying on them.
How do I convert JSON to TOON in JavaScript?
Install the official @toon-format/toon package from npm (npm i @toon-format/toon), then import { encode, decode } from "@toon-format/toon". Pass your JavaScript object or array to encode() to get a TOON string, and pass that string to decode() to get your data back. For a quick check without code, run npx @toon-format/cli input.json --stats.
Do I need a library or can I convert online?
No library required for one-off conversions. The free browser-based converter at json2toon.co handles JSON-to-TOON and back entirely in your browser — no data ever leaves your machine. Use the SDK when you need to automate conversions inside your application or CI pipeline.
Is TOON reversible (lossless)?
Yes, for all data types TOON supports. A round-trip encode → decode preserves values faithfully. TOON is a text format designed for readability and LLM consumption, so binary blobs should be base64-encoded before conversion, just as they would be in JSON.
How many tokens does TOON save compared to JSON?
According to the current official benchmark (v4.1, 5,856 LLM calls), TOON uses 42.6% fewer tokens than JSON. Flat, uniform datasets save 58.7%; the mixed-structure track saves 32.7%, and irregular data such as event logs saves as little as 15%.
Recommended Reading
Migrating to TOON v4: Breaking Changes and Upgrade Checklist
Upgrading from TOON v2/v3 to v4? Key folding is gone, # lines are now comments, and decoders must upgrade first. A step-by-step checklist with fixes.
Token-Efficient Apps with TOON and the Vercel AI SDK
How to format context as TOON inside Vercel AI SDK apps to cut input tokens—while keeping generateObject and tool calls on JSON for reliable structured output.
Few-Shot Prompting with TOON: Cheaper, Clearer Examples
Few-shot examples repeat in every prompt, so their format compounds. TOON-encoded example tables cut tokens; output examples should match your target format.