To minify JSON, you remove every byte a parser does not need: the spaces, tabs and newlines that help people read it but carry no meaning. You get the same data in fewer bytes, such as {"id":1,"name":"Ada"} instead of the same object over five indented lines.
This guide covers what minification removes, what it saves, and how to do it in JavaScript, Python and on the command line. It also explains how minification interacts with gzip and Brotli, and when to keep your JSON pretty-printed. For the opposite task, see How to format and beautify JSON.
What JSON minification does
JSON has two kinds of whitespace. Insignificant whitespace sits between tokens, such as the indentation before a key, the space after a colon or the newline at the end of a line. Significant whitespace sits inside string values, where a space or \n is real data. Minification removes all of the first kind and none of the second.
A minifier tokenizes the document and writes it back with the tokens packed together. There is no indentation, no line breaks, and exactly one comma or colon between neighbors. Numbers, booleans, null, key order and string contents stay byte-for-byte the same.
// Pretty (48 bytes)
{
"id": 1,
"name": "Ada",
"active": true
}
// Minified (35 bytes)
{"id":1,"name":"Ada","active":true}Some things did not change. The string "Ada" still has its quotes, and true is still a boolean. A value with a space in it, like "New York", keeps that space. A correct minifier only removes whitespace between structural tokens.
Why minify: payload size and performance
Minifying saves bytes. Pretty-printed JSON can be 15-50% larger than its minified form, depending on nesting depth and indent width. Each level of nesting adds leading spaces to every line inside it. For a document served millions of times a day, that overhead costs bandwidth, adds latency and fills cache entries.
Where the savings show up
- Network transfer. Fewer bytes on the wire means a faster time to last byte. This matters most on mobile and high-latency connections.
- Memory and cache. Minified payloads take less room in CDN edge caches, Redis and browser storage, so more entries fit in the same budget.
- Bundle size. JSON embedded in a JavaScript bundle, such as translation catalogs, config or seed data, ships to every visitor. Smaller JSON means a smaller critical-path download.
Minification does not make parsing much faster. A JSON parser skips whitespace in one cheap pass, so a minified document parses at about the same speed as a formatted one. The gain is in transfer and storage, not CPU. Keep that in mind if someone says minifying will fix a slow endpoint.
How to minify JSON in code
You rarely need a library for this. Mainstream JSON serializers emit minified output by default. Pretty-printing is the option you turn on.
JavaScript / Node.js
JSON.stringify with one argument produces minified JSON. The optional second and third arguments (a replacer and an indent width) add whitespace. Leave them out and you get the compact form.
const pretty = `{
"id": 1,
"tags": ["a", "b"]
}`;
// Parse, then stringify with no indent argument:
const minified = JSON.stringify(JSON.parse(pretty));
console.log(minified);
// {"id":1,"tags":["a","b"]}
// Compare: the third argument is what pretty-prints
JSON.stringify({ id: 1 }, null, 2);
// {\n "id": 1\n}Python
Python's json.dumps adds no newlines by default, but it leaves a space after every , and :. Pass the separators argument to remove them and match JSON.stringify output. See Working with JSON in Python for more.
import json
data = {"id": 1, "tags": ["a", "b"]}
# Default still has spaces after ',' and ':'
json.dumps(data) # '{"id": 1, "tags": ["a", "b"]}'
# Compact separators remove them
json.dumps(data, separators=(",", ":"))
# '{"id":1,"tags":["a","b"]}'Minify JSON with jq -c
jq is the standard command-line JSON processor, and jq -c . is the shortest way to minify JSON in a shell. The . is jq's identity filter, which outputs its input unchanged. -c (--compact-output) prints each result on one line with no whitespace between tokens. jq parses the input first, so invalid JSON fails with a parse error and a non-zero exit code. The minify step also validates.
# Minify a file to stdout
jq -c . data.json
# Save the minified copy next to the original
jq -c . data.json > data.min.json
# Minify a stream of API responses
curl -s https://api.example.com/items | jq -c .Minifying files in place
jq has no in-place flag. If you redirect output to the file you are reading (jq -c . a.json > a.json), the shell truncates it before jq reads it, and you get an empty file. Write to a temporary file and move it over the original only if jq succeeded. Or use sponge from moreutils, which waits for all input before writing.
# One file, safely
jq -c . data.json > data.json.tmp && mv data.json.tmp data.json
# With sponge (moreutils)
jq -c . data.json | sponge data.json
# Every .json file in a directory
for f in *.json; do
jq -c . "$f" > "$f.tmp" && mv "$f.tmp" "$f"
doneArrays to one object per line
jq -c '.[]' writes each element of a top-level array on its own line, minified. That is the NDJSON / JSON Lines format that log pipelines and bulk-import APIs expect. To go the other way, jq -c -s . (slurp) reads a stream of values and wraps them in one minified array.
# [{"id":1},{"id":2}] -> one object per line
jq -c '.[]' items.json > items.ndjson
# NDJSON -> one minified array
jq -c -s . items.ndjson > items.jsonKey order, Unicode and numbers
- Key order is preserved. jq keeps object keys in input order. Add
-S(--sort-keys) to sort them, which helps with stable diffs and hashing. See How to sort JSON keys. - Unicode stays literal. Non-ASCII characters are written as UTF-8. Add
-a(--ascii-output) to emit\uXXXXescapes instead. - Multiple documents stay separate. If the input has several top-level values,
jq -c .prints each one minified on its own line. It does not merge them. - Number precision depends on the jq version. jq 1.6 and earlier convert every number to a 64-bit float, so integers above 2^53 (such as 64-bit IDs) can be rounded without warning. jq 1.7 and later keep the precision of numbers that pass through unchanged, but may normalize the notation (
1E2becomes1E+2). Runjq --versionbefore you minify data with large IDs.
How minification interacts with gzip and Brotli
Most "always minify" advice skips this. HTTP responses are almost always compressed with gzip or Brotli, and compression is very good at shrinking repeated indentation and newlines. After compression, the gap between pretty and minified JSON is much smaller than the raw byte difference, often only a few percent.
If your server already gzips responses, minifying still gives a smaller but real gain and a lighter cache footprint. If you ship JSON *uncompressed*, for example embedded in a bundle, stored in a database column or sent over a raw socket, minification matters much more. Nothing else removes that whitespace.
When to minify JSON and when not to
Minify JSON at the point where it leaves your system. Keep it readable anywhere a person might look at it. In short, machines get minified JSON and people get formatted JSON.
| Situation | Minify? | Why |
|---|---|---|
| Production API responses | Yes | Smaller payloads, less cache pressure at scale |
| JSON embedded in a JS bundle | Yes | Ships to every visitor on the critical path |
| Config stored in a DB column or KV | Yes | Uncompressed storage benefits directly |
| Files committed to git | No | Minified diffs are unreadable, so you lose line-by-line review |
| Config files humans edit | No | Readability and merge-friendliness matter more than bytes |
| Log lines and debug output | No | You need to read these under pressure |
| Local development responses | Optional | Pretty-print to inspect, or minify to match production |
Source control is the main case to avoid. A minified file is one huge line, so git diff marks the whole file as changed even when one value moved, and review stops being practical. Commit formatted JSON and minify it in a build or deploy step. To compare two versions of a document, the JSON Diff tool compares structure, ignores formatting and shows only real changes.
Minification is lossless and safe to reverse
Minification removes no information. It only deletes whitespace between tokens, so you can run the output through a JSON Formatter and get a readable document back. It may not match the *original* byte for byte, since the indent style can differ. The values, types and structure are the same. Parse either version and you get identical objects.
Whitespace inside strings is safe with a correct minifier, because it sits inside quotes and is left alone. Be careful with tools that "minify" some other way. A correct minifier parses and re-serializes. A naive regex that deletes whitespace will corrupt any string with spaces or newlines. If you are unsure, run the result through a JSON Validator to check that it is still well-formed.