The same JSON document can be written on a single line with no spaces or spread across dozens of indented lines. Both forms are valid and carry identical data; the difference is who reads them. In this lesson you will learn how to pretty-print JSON for humans and minify it for machines using JavaScript, Python, the command line and your editor, and when each form is the right choice.
The JSON grammar allows four whitespace characters between tokens: space, tab, line feed and carriage return. A parser ignores all of them, so the minified and the indented version below are equal after parsing:
{"id":1042,"items":[{"sku":"A-1","qty":2}],"paid":false}{
"id": 1042,
"items": [{ "sku": "A-1", "qty": 2 }],
"paid": false
}Whitespace inside a string is significant: "New York" and "New York" are different values. Formatters only touch the whitespace between tokens.
JSON.stringify takes a third argument called space. A number from 1 to 10 sets the indentation width; a string of up to 10 characters is used verbatim as the indent unit.
const user = { name: "Ada", roles: ["admin", "dev"], active: true };
JSON.stringify(user); // {"name":"Ada","roles":["admin","dev"],"active":true}
JSON.stringify(user, null, 2); // indented with two spaces
JSON.stringify(user, null, "\t"); // indented with tabsThe second argument (null here) is the replacer, covered in the next lesson. Python's json.dumps uses keyword arguments instead:
import json
user = {"name": "Ada", "roles": ["admin", "dev"], "active": True}
print(json.dumps(user, indent=2, sort_keys=True))
print(json.dumps(user, separators=(",", ":"))) # smallest possible outputPython's default output, {"name": "Ada", ...}, keeps a space after each separator, so it is neither minified nor pretty. Pass separators=(",", ":") when size matters.
You will constantly inspect API responses and config files in a terminal. Three tools cover almost every case:
| Task | jq | Python |
|------|----|--------|
| Pretty-print | jq . data.json | python -m json.tool data.json |
| Minify | jq -c . data.json | python -m json.tool --compact data.json |
| Sort keys | jq -S . data.json | python -m json.tool --sort-keys data.json |
| Custom indent | jq --indent 4 . or jq --tab . | python -m json.tool --indent 4 |
jq is the most convenient because it also validates: a malformed file produces an error with line and column and a non-zero exit code. Pipe anything into it:
curl -s https://api.example.com/users/1 | jq .
jq . config.min.json > config.jsonIn editors the same job is a shortcut: VS Code formats a JSON document with Shift+Alt+F (Shift+Option+F on macOS), and Prettier handles whole projects with npx prettier --write "**/*.json".
Minified JSON is smaller, but the saving is often less than expected. Web servers gzip or brotli-compress responses, and whitespace compresses extremely well, so the difference on the wire is usually a few percent.
localStorage values, and JSON Lines files, where each record must occupy exactly one line.Key order is not part of the JSON data model, so {"a":1,"b":2} and {"b":2,"a":1} are the same object. Sorting keys (jq -S, sort_keys=True) is still useful because it produces a canonical form that is easy to diff, compare or hash.
JSON.stringify(text, null, 2) wraps an already-serialized string in more quotes. Parse first: JSON.stringify(JSON.parse(text), null, 2).jq and json.tool fail; formatters only re-space valid documents.What does `JSON.stringify(data, null, 2)` produce?
JSON.stringify(value, null, 2) pretty-prints and JSON.stringify(value) minifies; Python uses indent= and separators=.jq ., python -m json.tool and editor formatters pretty-print and validate files from the terminal.Next lesson: Advanced JSON.stringify and JSON.parse: replacer, reviver and toJSON — control exactly which properties are serialized and revive dates, BigInts and custom classes when parsing.