Developer Formatting

JSON formatter

What to do
Indent

Processed in your browser · nothing is uploaded

Local · errors reported with line and column

Formats JSON with the indent you choose, 2 spaces, 4, or a tab, and says exactly where it broke if it will not parse: line and column rather than a shrug. The same box minifies, sorts keys, flattens to dotted paths and back, strips empty values, reads JSON Lines into a single array, and evaluates a JSONPath expression against the document.

How to use the json formatter

1 Paste the JSON. It is formatted immediately, and any syntax error is located by line and column.
2 Pick another operation to do something else with the same document: minify, sort keys, flatten, unflatten, strip empty values, read JSON Lines into an array, or pull part of it out with a JSONPath expression.
3 Set the indent if two spaces is not your house style.
4 Copy the result, or save it as a file.

Almost every rejection comes down to one of three things, and all three are valid JavaScript, which is why they slip through. A trailing comma after the last element is fine in JS and illegal in JSON. Single quotes are fine in JS and illegal in JSON: strings must use double quotes. Unquoted keys are fine in JS and illegal in JSON. Two rarer causes are worth knowing: a byte order mark at the start of a file, which is invisible and breaks the parse on the very first character, and NaN or Infinity, which JavaScript produces happily and JSON cannot represent at all.

Everything past formatting is the same parse followed by a different way of writing the document out, which is why it all lives on one page. Minifying strips whitespace outside strings, typically 15 to 30 percent of a formatted document, though gzip has usually taken that saving already; it earns its keep where nothing compresses, such as a value in a database column or a string embedded in a page. Because the document is parsed and re-emitted rather than scanned for spaces, numbers are normalised on the way through: 1.0 comes back as 1 and 1e3 as 1000, and an integer above 9007199254740991 loses its last digits. Not a quirk of this tool but of every JavaScript consumer your JSON will meet, and the reason large IDs belong in strings.

Sorting keys is a diff tool in disguise. Key order means nothing to the standard and nothing to any parser, and everything to a text comparison, so two documents that differ only in field order produce a diff full of noise until both are sorted. Sorting is alphabetical at every level and leaves arrays alone, because array order is data rather than formatting. Two surprises: keys that look like non-negative integers always come first in numeric order, so "2" precedes "10", which is a JavaScript object rule rather than a choice made here; and duplicate keys do not survive the parse, so only the last one is left.

Flattening turns nesting into dotted paths, user.address.city, with array positions in brackets, which is what almost every flat-key system expects: translation files, feature flags, environment config, analytics payloads, a spreadsheet column. Unflattening rebuilds the nesting from those paths, reading a bracketed number as an array position and a name as an object key. The round trip is lossless for ordinary data and lossy in exactly one place: a key that already contains a dot cannot be told apart from nesting.

Removing empty values strips null, empty strings and empty containers, recursively, so an object left empty because its contents went is removed too. It deliberately keeps false and 0, which are values rather than absences. Be careful where an API treats an explicit null as "clear this field": dropping it says nothing at all instead, which is not the same instruction. And JSON Lines, one complete JSON value per line and also called NDJSON, becomes a single array, with the line number named when a row will not parse. A file rejected here is almost always a pretty-printed object spanning several lines, which is the one thing the format forbids.

JSONPath is the one operation that reads the document instead of rewriting it. The expression goes in the field under the input and the matching values come back as an array, in document order: $..author gathers every author at any depth, $.store.book[?(@.price < 9)] returns the books under nine. Dot and bracket notation both work, * is a wildcard, .. is recursive descent, a negative index counts back from the end and [0:2] is a slice. Filters are parsed rather than run through eval, which is how the original 2007 proposal worked and turns an untrusted expression into arbitrary code. The comparisons are ==, !=, <, <=, > and >=, plus a bare @.field as a presence test. A filter that does not begin with @.field is refused with a message; one that begins correctly and then asks for something unsupported — a regex match, a negation, two conditions joined with && — falls back to the presence test on that first field instead of erroring, and quietly returns everything that carries it. A filter matching far more than you expected is nearly always that. Two things catch people out: the syntax was only standardised in 2024, as RFC 9535, so implementations written before it genuinely disagree about descent and filters; and recursive descent really does search every depth, which is why $..price in the sample document finds the bicycle as well as the books.

What people use it for

  • Making an unreadable API response readable
  • Stripping whitespace before storing JSON in a database column
  • Sorting keys so two documents diff cleanly
  • Flattening nested JSON into dotted paths for a spreadsheet
  • Rebuilding nesting from a flat set of dotted keys
  • Clearing nulls and empty fields out of a payload
  • Turning an NDJSON export into a single array
  • Pulling every value at one path out of an API response

Questions

The three usual causes are a trailing comma after the last item, single quotes instead of double, and unquoted keys. All three are valid JavaScript and none is valid JSON.

ECMA-404; the JSON data interchange syntaxMDN, JSON.parse()
Was this tool any good?
Internal signal only · I use it to find the tools worth rebuilding