9 min read

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.

By json2toon.co

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

LanguagePackageInstallStatus
TypeScript / JavaScript@toon-format/toonnpm i @toon-format/toonOfficial reference — MIT
Pythontoon-pythonpip install --pre toon-formatOfficial, beta (0.9.0b1) — MIT
CLI@toon-format/clinpx @toon-format/cli input.json --statsOfficial — MIT
Rust, Java, Go, .NET, Swift, Dart, Juliacommunity portssee GitHub orgOfficial 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/toon

Encode: 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 })); // true

The 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 older indent option, which still works but is deprecated.
  • delimiter: "," (default), "\t", or "|" for tabular rows and inline arrays.
  • replacer: a JSON.stringify-style (key, value, path) function; return undefined to 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, default true): validates array lengths and row counts, and throws ToonDecodeError (since 2.2.0, a SyntaxError subclass with line and source fields).
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.git

The 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,delivered

Spec 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,delivered

On 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.

  1. Identify hot paths. Profile which prompts consume the most tokens. Prioritise those — converting cold paths adds complexity for minimal gain.
  2. 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.
  3. Install and pin the package. Use npm i @toon-format/toon or pip 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.
  4. Replace the serializer at prompt-build time. Swap your JSON.stringify(data) (or json.dumps(data)) call for encode(data) in the one place that builds the LLM context string.
  5. Test the round-trip. Add a unit test asserting decode(encode(data)) deep-equals the original object. Run it in CI on representative fixtures.
  6. 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.
  7. Measure token counts before and after. Log usage.prompt_tokens from your LLM API response. Confirm the savings match expectations before rolling out broadly.
  8. 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

TOONPythonJavaScriptTypeScriptTutorialSDK