What minifying does
Minifying JSON removes every character the grammar does not require: the newlines, the indentation, and the spaces after colons and commas.
{
"id": 42,
"roles": ["admin", "engineer"]
}
becomes
{"id":42,"roles":["admin","engineer"]}
68 bytes down to 38 — a 44% reduction. The parsed value is byte-for-byte identical in meaning, because whitespace between tokens is insignificant under RFC 8259.
The part most advice gets wrong
That 44% looks compelling, and it is the number most articles stop at. It is also misleading for the most common use case, because your API responses are already compressed.
Gzip and Brotli work by finding repeated sequences. Indentation is the most repetitive content in a formatted document — the same run of spaces, thousands of times. Compression removes it almost entirely on its own.
Rough shape of the result for a typical API payload:
| Raw | After gzip | |
|---|---|---|
| Formatted (2-space) | 100 KB | ~12 KB |
| Minified | 56 KB | ~11 KB |
The 44% raw saving collapses to low single digits once compression is applied, because gzip had already eliminated nearly all of what minifying removes. Exact figures depend on the data — deeply nested documents with short values benefit more than flat ones with long strings — but the shape holds.
The practical conclusions:
- If compression is off, turning it on is worth vastly more than minifying.
- If compression is on, minifying API responses buys you very little.
Verify rather than assume — check whether your responses carry content-encoding:
curl -sI -H "Accept-Encoding: gzip, br" https://api.example.com/users | grep -i content-encoding
No header means compression is off, and that is the thing to fix.
When minifying genuinely matters
There are real cases, and they share one property: no compression layer downstream.
- URL query strings — JSON in a query parameter, where browsers and servers impose practical length limits and nothing is compressed.
- HTML
data-attributes — inline in the document; the surrounding HTML may be compressed, but shorter is still better for parse time. - Cookies — a hard 4 KB limit per cookie, uncompressed.
- Message queues — SQS, Kafka, and others impose per-message size caps.
localStorage/sessionStorage— roughly 5–10 MB per origin, uncompressed.- QR codes — capacity is measured in hundreds of bytes, so every character counts.
- Embedded and IoT — where the parser itself is the constraint.
In all of these the saving is real, because nothing else is going to remove that whitespace for you.
When not to minify
Anything in version control. A minified file is one line. Every change reports the whole file as modified. Review is impossible, and merge conflicts are unresolvable by hand. This covers package.json, tsconfig.json, composer.json, fixtures, seed data, and translation files.
Configuration files humans edit. Minified config is hostile to the next person who has to change it, including you.
Anything you might need to debug. If it can appear in a log or an error report, keep it readable.
Files served with compression already enabled — as above, you are optimising something that has already been optimised.
Minifying in code
// JavaScript — omit the space argument
const minified = JSON.stringify(JSON.parse(raw));
# Python — the default separators include a space after ", " and ": "
import json
minified = json.dumps(json.loads(raw), separators=(",", ":"))
# jq
jq -c . input.json > output.min.json
Python's default is the one to watch: json.dumps(obj) is not minimal, because it writes ", " and ": ". Without the separators argument you leave two bytes per pair on the table.
Reducing size properly
If payload size is genuinely a problem, minifying is the smallest lever available. These matter more:
- Enable Brotli or gzip. By far the largest single win.
- Return fewer fields. Sparse fieldsets (
?fields=id,name) or GraphQL let clients ask for what they need. - Paginate. A 10 MB response is a design problem, not a compression problem.
- Shorten repeated keys. In an array of 50,000 objects, the keys are most of the document — a columnar layout (
{"cols":["id","name"],"rows":[[1,"Ada"]]}) can cut size dramatically at the price of readability. - Consider a binary format. For high-throughput internal traffic, Protocol Buffers, MessagePack, or Avro beat JSON on both size and parse speed. You lose human readability, which is usually the reason JSON was chosen.
Reach for (5) only when (1) through (4) are exhausted — debuggability is worth a great deal.
Related
- JSON Formatting — the inverse operation
- JSON Best Practices — designing smaller payloads
- JSON Formatter — minify and format in one place