What formatting JSON actually does
JSON is defined by RFC 8259 and ECMA-404, and in that grammar the whitespace between tokens carries no meaning at all. Formatting therefore parses your text into a value and writes it out again with the indentation you picked — it never edits the characters in place. Whatever survives the round trip is data; whatever disappears was never part of the document.
That round trip is why formatting doubles as validation. If the parser refuses the input you get a line, a column and a caret instead of output, so a successful format is proof that the document is well-formed JSON rather than merely plausible-looking text.
Two changes are deliberate. Duplicate keys collapse — RFC 8259 leaves them undefined and JavaScript keeps the last one — so a key that vanishes was declared twice. And keys that look like non-negative integers ("0", "12") are emitted in numeric order ahead of the others, because that is how JavaScript objects order their properties.
Beautify or minify: which output to take
Indented output is for humans and for diffs: two spaces is the default across the npm and JavaScript ecosystem, four spaces is common in Python and .NET tooling, and a tab keeps the file aligned with Go and Makefile conventions. Whichever you choose, use the same one across a repository so version control shows content changes rather than whitespace churn.
Minify strips every optional space and newline and reports how many bytes that saved. On a pretty-printed config file the saving is typically 20–40 %, but on the wire it matters far less than it looks: gzip and Brotli compress repeated indentation almost to nothing, so minifying a response that is already compressed buys single-digit percentages.
Minifying is worth it where compression does not reach: a JSON blob embedded in a data attribute, a value stored in localStorage or a database column, or a payload counted against a size limit such as a cookie, a query string or an SQS message.
Reading a JSON syntax error
An invalid document produces a line, a column, the offending source line and a caret under the exact character. The position comes from the engine when it reports one and from our own scanner otherwise, because V8, SpiderMonkey and JavaScriptCore word the same failure differently — "Unexpected token }" in one browser is "JSON.parse: expected property name" in another.
Almost every real-world failure is one of these:
- A trailing comma before } or ] — legal in JavaScript, never in JSON.
- Single quotes, or unquoted keys ({name: 1}) — JSON strings and keys need double quotes.
- // or /* */ comments: JSONC and JSON5 allow them, RFC 8259 does not. Strip them, or keep the file as .jsonc and format the stripped copy.
- NaN, Infinity, undefined, or Python’s True / False / None instead of true / false / null.
- A raw newline or tab inside a string: every character below U+0020 must be escaped as \n, \t or \u00XX.
- Several objects pasted one after another (NDJSON / JSON Lines): that is a stream of documents, not one document.
Sorting keys and comparing two files
Sorting orders object keys with a numeric-aware collator, so item2 lands before item10 instead of after it. "Include nested objects" applies the same order at every level. Array order is never touched: in JSON the position of an array element is data, and reordering it changes the document’s meaning.
This is what makes two exported files comparable. Format both with the same indent and sorted keys, then run the two outputs through Text Diff: what remains is the change you were looking for, with no noise from a serialiser that emitted keys in a different order.
Big integers, floats and other precision traps
JSON numbers have no size limit, but JavaScript reads every one of them into a 64-bit double, which is exact only up to 9,007,199,254,740,991 (2^53 − 1). A 64-bit Snowflake ID such as 7223372036854775807 comes back as 7223372036854775800 — a valid-looking value that points at no record. "Preserve big integers" keeps those literals verbatim, as strings.
Fractions have the same problem in a quieter way: 0.1 + 0.2 is 0.30000000000000004, and a literal written as 1.0 or 1e2 is re-emitted as 1 or 100 because the double carries no memory of how it was typed. Money and measurements survive best as strings or as integer minor units (cents, won), never as floats.
The warning above the output counts the integer literals in your input that cannot survive a double, so you can see the risk before you copy the result into a ticket or a test fixture.
What the statistics tell you
Keys counts every object member in the document, arrays counts every array, and depth is the deepest level of nesting. Depth is the practical one: many schema validators, database JSON columns and API gateways cap nesting (commonly between 32 and 100 levels), so a document that formats here can still be rejected downstream.
Input bytes, output bytes and the saved percentage are UTF-8 byte counts, not character counts — the difference matters as soon as the document contains Korean, emoji or accented Latin, where one character costs two to four bytes.
Where your JSON goes (nowhere)
Parsing, sorting, minifying and the error scan all run in this tab with the browser’s own JSON parser. There is no upload, no account and no "load from URL" button — fetching a URL would require a server to make the request on your behalf, which is exactly the property this page is built to avoid.
Your draft is kept in this browser’s localStorage so a reload or an accidental tab close does not lose it. It stays on this device, is readable only by this site, and the Clear button removes it — worth pressing on a shared or public machine.