Minifying JSON

What JSON minification does, how much it really saves once gzip is involved, when to minify, and when leaving JSON formatted is the better decision.

6 min read

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.

Minify your JSON →

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:

RawAfter gzip
Formatted (2-space)100 KB~12 KB
Minified56 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:

  1. Enable Brotli or gzip. By far the largest single win.
  2. Return fewer fields. Sparse fieldsets (?fields=id,name) or GraphQL let clients ask for what they need.
  3. Paginate. A 10 MB response is a design problem, not a compression problem.
  4. 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.
  5. 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

Frequently asked questions

Does minifying JSON make my API faster?

Rarely by a meaningful amount. Production HTTP traffic is almost always gzip- or Brotli-compressed, and compression handles repeated whitespace extremely efficiently — indentation compresses to nearly nothing because it is the most repetitive content in the document. Minifying before compression typically saves low single-digit percentages of transferred bytes. Enabling compression, if it is off, matters far more than minifying.

Does minifying JSON change the data?

No. Minifying removes only insignificant whitespace between tokens, which RFC 8259 defines as having no meaning. The parsed value is identical. Numbers may be re-spelled by the serialiser (1.50 becomes 1.5) because they round-trip through a double, but their value does not change.

Should I commit minified JSON to Git?

No. A minified file is one enormous line, so every change produces a diff that shows the entire file as modified, making review impossible and merge conflicts unresolvable. Commit formatted JSON and minify at build time if you need to. This applies to package.json, tsconfig.json, fixtures, and any data file a human might read.

When is minifying JSON genuinely worth it?

When the JSON has to fit somewhere with a hard size limit and no compression: a URL query string, an HTML data- attribute, a cookie, a message queue with a payload cap, a QR code, or a localStorage entry. In those cases every byte is real, because nothing downstream will compress it for you.

More in JSON Guide

← Back to JSON Guide