JSON Minification: What It Saves and What It Does Not

By Wesley · · 6 min read

Minifying JSON means removing the whitespace that sits between tokens: indentation, line breaks and the space after each colon and comma. The data is unchanged. What is less obvious is how much that actually saves once compression is involved, and when a single-line document is a requirement, not an optimization.

What counts as removable whitespace

The JSON grammar (RFC 8259) allows four whitespace characters between tokens: space, tab, line feed and carriage return. They carry no meaning, so all of them can go. Whitespace inside a string is data and must be kept, which is why minifying with a regular expression is a bad idea: a pattern that strips spaces cannot tell "New York" from indentation.

Before: 76 characters
{
  "city": "New York",
  "tags": [
    "a",
    "b"
  ],
  "active": true
}
After: 50 characters
{"city":"New York","tags":["a","b"],"active":true}

How much smaller, measured

To put numbers on it, we generated a document with 200 user records (id, name, email, a boolean, a two-item array and a nested address object) and measured it in several forms with Node.js.

Size of one document in different forms
Pretty, 4-space indent
67,726
Pretty, 2-space indent
50,122
Minified
28,114
Pretty (2-space) + gzip
3,099
Minified + gzip
2,833
Pretty (2-space) + Brotli
1,693
Minified + Brotli
1,465
bytes
Same 200-record document. gzip at level 6 and Brotli at its default quality, via Node's zlib module.

Two things stand out:

  • Uncompressed, minifying is a big win. The minified file is 44% smaller than the 2-space version and 58% smaller than the 4-space version. Deeply nested data saves even more, because indentation grows with depth.
  • After compression, the gap almost disappears. With gzip the difference is 266 bytes (about 9%). Repeated runs of spaces are the easiest thing in the world for a compressor to encode.

So if your API already serves responses with gzip or Brotli, minifying mainly saves a little CPU and memory for parsing, not much bandwidth. The cases where it matters are the ones where nothing compresses the data for you.

When one-line JSON actually matters

  • JSON Lines / NDJSON. These formats store one JSON value per line, so each record must be on a single line. The same goes for most structured log pipelines, which split entries on newlines.
  • Environment variables and CLI arguments. Multi-line values are awkward to quote in shells, .env files and CI settings. A one-line value avoids a whole class of quoting bugs.
  • Storage that is not compressed. Rows in a text column, cache entries, and browser localStorage (limited to roughly 5 MB per origin) store exactly the characters you give them.
  • Embedding JSON in other things. HTML attributes, URL parameters, config templates and test fixtures are easier to handle when the value has no line breaks.
  • LLM prompts. Indentation and newlines are tokens too. Minifying a large JSON input before sending it to a model reduces the bill; see the TOON article for going further.

What a minifier can change by accident

Most minifiers, including the one on this site and JSON.stringify(JSON.parse(text)), do not edit the text. They parse it into values and print those values again. That is safe for whitespace, but anything the parser cannot represent exactly comes out different.

InputAfter parse + print in JavaScriptWhy
90071992547409939007199254740992Integers above 2^53 are not exact in a 64-bit float
1.501.5Trailing zeros are not part of the number
1e400nullOverflows to Infinity, which JSON cannot express
{"a":1,"a":2}{"a":2}Duplicate keys: the last one wins
{"b":1,"2":0,"1":0}{"1":0,"2":0,"b":1}Integer-like keys are moved first, in ascending order

None of this affects typical data. It matters when the document carries large numeric IDs (send those as strings), money with fixed decimals, or when the exact bytes are signed or hashed. For those, minify with a tool that works on the token stream, or keep the original.

Minifying from the command line and in code

# jq: -c prints compact output
jq -c . data.json > data.min.json

# Python 3.9+
python -m json.tool --compact data.json

# Node.js
node -e "process.stdout.write(JSON.stringify(JSON.parse(require('fs').readFileSync(0))))" < data.json

In code, watch the defaults. JavaScript's JSON.stringify(value) is compact unless you pass an indent argument. Python's json.dumps(value) is not: it puts a space after each comma and colon, so compact output needs explicit separators.

Python
json.dumps(value)                         # {"a": 1, "b": [1, 2]}
json.dumps(value, separators=(",", ":"))  # {"a":1,"b":[1,2]}

A quick one-off

Convert JSON To OnelinePaste JSON, get a single line, copy it. Nothing is uploaded.
Need the opposite direction? The Nested JSON Parser formats one-line JSON into a readable tree and also decodes JSON that was stored as an escaped string.