TokenPad

Guide · 7 min read

Why your JSON costs three times more tokens than you think

Indentation, repeated keys and structural punctuation can be half the tokens in a JSON payload. Where they go, and the three changes that remove them without losing information.

Published August 3, 2026

Contents
  1. Where the tokens go
  2. Indentation is pure overhead
  3. Repeated keys in arrays
  4. Three fixes, in order of return
  5. Does minifying hurt accuracy?

English prose runs about four characters per token. Pretty-printed JSON runs about 2.2. That means the same information, expressed as structured data, costs roughly twice as many tokens — and most of the difference is structure the model gains nothing from.

Where the tokens go

Take a small object, formatted the way every editor formats it by default:

{
  "user": {
    "id": 10482,
    "email": "ana@example.com"
  }
}

Minified, that same object is dramatically cheaper — commonly half the tokens or better on a nested structure, and nothing about its meaning changed. Run both versions through the tokenizer playground and the reason is immediately visible: whole blocks are spent on leading spaces.

Three categories of overhead, in order of size:

  • Indentation. Two to four tokens per line, on every line.
  • Punctuation. Braces, brackets, colons, commas and quotes each take a token, and a nested object has a lot of them.
  • Repeated keys. In an array of objects, every key is repeated once per element.

Indentation is pure overhead

The vocabularies do include some whitespace merges, so a run of spaces is not always one token per space. But it is never free, it scales with nesting depth, and it recurs on every line of every request forever.

There is no evidence that indentation improves a model's comprehension of well-formed JSON. The structure is carried entirely by the punctuation; the layout is a convenience for human readers. Minify what you send to the model and keep the pretty version in your logs, where a human actually reads it.

Repeated keys in arrays

This is the one people miss, and at scale it is larger than indentation. An array of 500 objects with six fields each repeats those six key strings 500 times — 3,000 key repetitions carrying six keys worth of information.

The fix is to send the schema once and the data as rows:

{"columns":["id","name","status"],
 "rows":[[1,"Ana","open"],[2,"Luis","closed"]]}

Models handle this format without difficulty as long as the column list is present and adjacent. On a large tabular payload it routinely halves the token count again after minification. Measure both shapes against your real data in the token counter before committing to it.

Three fixes, in order of return

  1. Minify. Zero risk, zero information loss, typically 30–50% on a nested payload. The prompt optimizer does this and shows the annual value at your request volume.
  2. Send only the fields the model needs. Payloads are usually serialised straight from an internal object, carrying timestamps, internal IDs, audit fields and nulls that no instruction ever references. Projecting to the fields actually used often beats minification.
  3. Flatten tabular data to columns and rows. More work, and worth it above a few hundred records.

Beyond those, two habits: never put base64 in a prompt if there is any alternative — it encodes at roughly one token per two characters and is almost always avoidable — and prefer compact ISO dates over verbose formatted ones.

Does minifying hurt accuracy?

No, for well-formed JSON. The model parses structure from the punctuation, and the punctuation is unchanged. What does hurt accuracy is ambiguity about where the data ends and your instructions begin — which is a delimiter problem, not a formatting one. Wrap the payload in a tag such as <data> and the ambiguity disappears for a handful of tokens. The prompt builder applies that structure by default.

The genuine caveat is that if you ask the model to produce JSON, its output formatting is a separate matter — and there you should ask for compact output too, since output costs four to six times what input does.

One last thing worth knowing: the same effect applies to source code, which runs about 2.7 characters per token for the same reasons. If you are sending repositories to a model, the arithmetic above is your arithmetic. Start from how to reduce LLM API costs for the full ordered list.

Tools referenced here

Read next