Minify JSON for Production: Real Size Savings, Gzip, and Minifiers That Change Your Data

Minifying JSON removes the whitespace that makes it readable: indentation, line breaks and the spaces after `:` and `,`. The data stays the same, and the file often shrinks by a third or more. Whether that matters depends on something else entirely: whether the response is already compressed. Below are measurements for both cases, the minify commands for jq, Python and Node.js, and the minifiers that quietly change more than whitespace.

What minification removes

JSON allows whitespace between tokens and ignores it. Minification removes all of it, leaving only whitespace inside strings, which is data.

{
  "id": 42,
  "name": "Ada Lovelace",
  "roles": [
    "admin",
    "editor"
  ]
}

{"id":42,"name":"Ada Lovelace","roles":["admin","editor"]}

A lossless minifier works on tokens: it copies strings, numbers and literals exactly as written and drops everything between them. That distinction matters later, because many popular "minifiers" work differently.

How much it actually saves

Here is a realistic API response, 200 product objects with nested fields, measured as pretty-printed with two-space indentation and as minified, then compressed the way a web server would send it:

                raw        gzip      brotli
pretty-printed  52.1 KB    3.5 KB    1.9 KB
minified        29.3 KB    3.2 KB    1.6 KB
saving          44%        ~9%       ~16%

Uncompressed, minification cut the size by almost half, because indentation grows with nesting depth. With compression, most of that difference disappears: repeated runs of spaces are exactly what gzip and Brotli remove best. Your numbers will vary with structure, but the pattern holds.

So minification is worth the most where compression is missing: JSON stored in databases, caches and queues; embedded in HTML inside <script type="application/json">; kept in localStorage with its roughly 5 MB quota; sent by servers that do not compress; and in JSON Lines logs, where one record must fit on one line anyway. For HTTP APIs, enable compression first. It saves far more than minifying does.

Minifying in each environment

# jq: -c for compact output
jq -c . pretty.json > min.json

# Python (no third-party packages)
python3 -c "import json,sys; json.dump(json.load(sys.stdin), sys.stdout, separators=(',',':'))" < pretty.json

# Node.js
node -e "process.stdout.write(JSON.stringify(JSON.parse(require('fs').readFileSync(0,'utf8'))))" < pretty.json
// In application code, compact output is the default
JSON.stringify(data);              // minified
JSON.stringify(data, null, 2);     // pretty-printed, for debugging only
import json
json.dumps(data)                           # '{"a": 1, "b": 2}' - spaces after : and ,
json.dumps(data, separators=(',', ':'))    # '{"a":1,"b":2}'    - fully compact

Python's json.dumps is not fully compact by default: it adds a space after every : and ,. Pass separators explicitly. PHP's json_encode is compact by default and only pretty-prints with JSON_PRETTY_PRINT. It also escapes / as \/ and non-ASCII characters as \uXXXX unless you add JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, which often saves more bytes than removing whitespace.

Minifiers that change your data

The commands above parse the JSON into native values and serialise it again. That is not purely a whitespace change, and the differences are silent. The same input through JSON.stringify(JSON.parse(…)) in Node.js:

input : {"id":12345678901234567890,"price":1.0,"a":1,"a":2,"s":"\u00e9"}
output: {"id":12345678901234567000,"price":1,"a":2,"s":"é"}

Large integers lose precision. JavaScript numbers are 64-bit floats, exact only up to Number.MAX_SAFE_INTEGER (9007199254740991), so a 64-bit ID from a database or Twitter/X-style snowflake ID is rounded. This is why many APIs send large IDs as strings as well. 1.0 becomes 1, which is harmless for most consumers but breaks byte-for-byte comparisons and some typed deserialisers. Duplicate keys collapse to the last value. And escape sequences are normalised, so the bytes of every string may change.

jq keeps large integer literals intact since version 1.7 as long as it does not do arithmetic on them. Python's json module keeps arbitrary-size integers. Neither keeps duplicate keys. When the exact bytes matter, because a signature, a checksum or a content hash is computed over the JSON, do not re-serialise at all. Sign the minified bytes you actually send, or use a canonical form such as RFC 8785 JSON Canonicalization Scheme on both sides.

Minification is not validation, and not JSONC

A token-level minifier may pass invalid JSON straight through, and a parse-based one rejects it. Neither fixes it. If the source is JSON with comments (JSONC, as used by tsconfig.json and VS Code settings) or JSON5, strip comments and trailing commas with a tool that understands that format, or the result will not parse as JSON.

Validate after minifying in a build pipeline: jq empty min.json exits with an error on invalid input and prints nothing otherwise.

Keeping development readable

Minify at the edge, not in the source. Keep configuration, fixtures and test snapshots pretty-printed in the repository so diffs stay readable, and minify during the build or at serialisation time. When debugging a minified response, format it locally with jq . or the browser's JSON viewer rather than asking the server for a pretty variant. Pretty-printing on every request costs CPU for bytes that compression would have removed anyway.

Sources and further reading

RFC 8259 defines JSON and its insignificant whitespace, and notes that object names should be unique. RFC 8785 defines the JSON Canonicalization Scheme. MDN documents JSON.stringify and Number.MAX_SAFE_INTEGER. The jq 1.7 release notes describe preserving large number literals, and the Python json and PHP json_encode documentation cover separators and the escaping flags.

Frequently asked questions

What does a JSON minifier do?

It removes whitespace between tokens (indentation, line breaks and spaces after `:` and `,`) without changing the data. The result is a single compact line.

How much smaller does minified JSON get?

Often 30–50% for indented JSON before compression. After gzip or Brotli the difference usually shrinks to around 5–15%, because compression already removes repeated whitespace efficiently.

Should I minify JSON API responses?

Enable HTTP compression first; it saves far more. Most frameworks already send compact JSON by default. Minification matters most for JSON stored or transmitted without compression.

How do I minify JSON on the command line?

`jq -c . file.json`, or with Python: `json.dump(obj, f, separators=(',', ':'))`. In Node.js, `JSON.stringify(obj)` without a spacing argument is already minified.

Can minifying JSON change the data?

Minifiers that parse and re-serialise can. In JavaScript, integers above 9007199254740991 lose precision, `1.0` becomes `1`, duplicate keys collapse and escapes are normalised. Use a token-based minifier when exact values matter.

Can I minify JSON with comments?

Standard JSON has no comments. For JSONC or JSON5 files, use a tool that understands that format to strip comments and trailing commas first, or the output will not be valid JSON.