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.
Contents
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
- 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.
- 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.
- 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
- Prompt Token OptimizerCuts whitespace, minifies JSON, collapses blank lines. Shows tokens saved and the annual value.
- Tokenizer PlaygroundEvery token rendered separately, with its ID. The fastest way to understand why a prompt is expensive.
- LLM Token CounterReal BPE tokenization, not characters ÷ 4. Shows which counts are exact and which are estimates.
Read next
- How to reduce LLM API costs — Nine levers, ordered by what they return per hour of work. Most teams find 40% in the first three.
- What is a token in an LLM? — The unit everything else is denominated in. Start here if tokens are still fuzzy.