JSON that comes off an API is almost always minified — one long line with no whitespace. That's the right choice for network transfer, but it's useless when you're trying to debug a response at 2am. Formatting (or "beautifying") JSON adds consistent indentation and line breaks so a human can actually read the structure.

This isn't complicated stuff, but there are a handful of details that catch people out. Let's go through what formatting actually does, when it matters, and where things go sideways.

What formatting JSON actually means

Formatting doesn't change the data. It changes the whitespace. A formatter parses the JSON into an in-memory structure and then re-serialises it with newlines and indentation. Because it parses first, a formatter also doubles as a validator — if your JSON is broken, it'll refuse to format and tell you roughly where.

Take this minified blob:

{"id":42,"name":"Ada","roles":["admin","editor"],"active":true,"meta":{"created":"2024-01-05","lastLogin":null}}

Formatted with two-space indentation, it becomes:

{
  "id": 42,
  "name": "Ada",
  "roles": [
    "admin",
    "editor"
  ],
  "active": true,
  "meta": {
    "created": "2024-01-05",
    "lastLogin": null
  }
}

Same bytes of data, wildly different readability. Now you can see the nesting, spot the null, and count the array elements at a glance.

When you'd reach for it

  • Debugging API responses. Paste a raw response somewhere readable before you start hunting for the field that's missing.
  • Reviewing config files. package.json, tsconfig.json, a Terraform state file — anything you're editing by hand is easier to read formatted.
  • Diffing. Two minified objects on one line each produce a useless diff. Format both first and your version control tool shows exactly which key changed.
  • Committing fixtures. If you store JSON test fixtures in a repo, keep them formatted so future changes produce clean, reviewable diffs.

The flip side: don't ship formatted JSON over the wire in production. Minify it. Those extra spaces and newlines add up across millions of requests, and gzip only recovers some of it.

Common gotchas

Trailing commas

JavaScript objects allow a trailing comma. JSON does not. This is the single most common reason a paste fails to parse:

{
  "a": 1,
  "b": 2,   // <- this comma is illegal in JSON
}

If you copied an object literal out of your source code, strip that last comma. Same goes for comments — // and /* */ are not valid JSON either, even though plenty of tools quietly tolerate them.

Single quotes

JSON strings must use double quotes. {'name': 'Ada'} is a Python dict or a JS object, not JSON. A strict parser rejects it outright.

Tabs vs spaces vs "two or four"

Pick an indentation style and be consistent, ideally matching your project's existing files. Two spaces is the de facto default for JSON in the JavaScript world. If your linter or an .editorconfig already dictates something, follow that — otherwise you'll create noisy diffs every time someone reformats.

Key ordering

Most formatters preserve the original key order. Some can sort keys alphabetically, which is handy for diffing but destructive if order carries meaning to you. Know which mode you're in before you paste something back into a live file.

Number precision and big integers

JSON has one number type, and it maps to a double in most languages. If your payload contains a 64-bit ID like 9007199254740993, round-tripping through a naive parser can silently mangle it. Formatting itself is usually text-safe, but be wary of any tool that re-parses numbers into floats. When precision matters, keep large IDs as strings.

Encoding and BOM

A stray byte-order mark at the start of a file will break strict parsers with a confusing error pointing at position zero. If a file looks perfectly valid but won't parse, check for a hidden BOM or non-breaking spaces pasted in from a rich-text source.

A short worked example

Say you hit an endpoint from the terminal and get this back:

{"status":"ok","data":{"users":[{"id":1,"name":"Ada","tags":["a","b"]},{"id":2,"name":"Grace","tags":[]}],"page":1,"total":2}}

If you have Python handy, you can format it inline:

echo '{"status":"ok","data":{"users":[...]}}' | python -m json.tool

Or with jq, which formats by default:

curl -s https://api.example.com/users | jq .

Both give you the same readable tree. In Node you'd do it programmatically:

const formatted = JSON.stringify(JSON.parse(raw), null, 2);
console.log(formatted);

That null, 2 is the important bit — the second argument is a replacer (leave it null), and the third is the indent width. Swap in "\t" for tabs.

When you don't want to reach for a terminal — you're on a locked-down machine, or you just want to eyeball a response quickly — paste it into a browser-based JSON Beautifier. It parses, validates, and pretty-prints in one step, which also tells you immediately if the payload is malformed.

A few habits worth adopting

  • Validate before you format. A formatter that fails is telling you the data is broken — that's a feature, not a nuisance.
  • Keep committed JSON formatted and minify only at build or serve time.
  • Match your project's indentation. Consistency beats personal preference.
  • Treat large integers as strings if any part of your stack touches them as numbers.

Formatting JSON is a two-second task that saves you from squinting at a wall of text. Wire it into your editor, your terminal, or a quick web tool — whichever gets you reading the actual structure fastest. The goal is always the same: see the shape of your data clearly enough to trust what's in it.

Photo by Chris Ried on Unsplash