JSON Formatter and Validator
Pretty-print or minify JSON, with the parse error pointed at the line that broke it.
Updated
Parsing and formatting happen in your browser. Nothing is uploaded, stored, or written into the page URL, which matters when the payload is a real API response.
Formatted
{
"tool": "json-formatter",
"runsInBrowser": true,
"limits": {
"upload": null,
"depth": {
"reported": true,
"counted": "arrays and objects"
}
},
"tags": [
"format",
"minify",
"validate"
]
}- Nesting depth
- 3
- Keys
- 8
- Objects and arrays
- 3 and 1
- Minified size
- 166 B
- Minifying saves
- nothing, it is already minified
JSON has no comments and no trailing commas, and duplicate keys are not an error: the last one silently wins. If a payload only parses in your editor, one of those three is usually why.
In short
Why does my JSON say invalid when it looks fine?
Almost always one of three things JSON forbids and JavaScript allows: a comment, a trailing comma, or a string in single quotes. None of the three is legal JSON. This page gives you the line and column rather than a bare verdict, so the trailing comma in its own broken sample is reported at line 3, column 25.
Two more silent traps: duplicate keys are legal and the last one quietly wins, and any integer above 9,007,199,254,740,991 loses precision the moment it is parsed.
How to use the JSON formatter and validator
Paste on the left and the formatted document appears on the right, updated on every keystroke. Below it the panel reports the nesting depth, the number of keys, how many objects and arrays the document holds, its minified size, and how many bytes minifying would save against what you pasted.
Depth is the figure people underestimate. A response that reads as flat often nests four or five levels once you count every wrapper object, and deep nesting is what makes a payload hard to consume. Each array or object opens one more level, while a string, a number, a boolean and null open none.
30.0%
Saved by minifying
the sample at 2 spaces, 237 to 166 bytes
41.8%
Saved at 4 spaces
285 bytes down to 166
22.1%
Saved with tabs
213 bytes down to 166
Those three figures are the same document formatted three ways, and they answer a common argument. Pretty printing is not free, but the cost is whitespace and whitespace compresses to almost nothing. Once the response is gzipped or Brotli compressed the difference between the four versions is close to noise.
Sorting keys is the underrated switch. JSON objects have no defined order, so two servers can send the same data in different sequences and produce a diff full of moved lines. Sorting recursively before comparing collapses that noise, and it makes a payload easier to scan when you are looking for a field by name.
Nothing you paste leaves your browser. Parsing, formatting and measuring all happen on this page, with no upload, no logging, and nothing written into the page URL. Real API responses carry real customer data, and this tool is built so that pasting one here does not become a disclosure.
Do
- Read the line and column before rereading the whole document.
- Sort keys on both payloads before diffing two API responses.
- Ask the API to send identifiers above 2^53 as strings.
- Minify for the wire and pretty print for the file in your repository.
- Match the indent your linter already enforces, whichever one that is.
Don't
- Put comments in a file that a strict JSON parser has to read.
- Assume a duplicate key is an error, because it parses and the last wins.
- Trust that a very large identifier survived the round trip unchanged.
- Paste a production response containing customer data into an online validator.
- Count on trailing commas because your editor and your bundler tolerate them.
The mistakes that stop a JSON document parsing, what the parser calls each one, and the fix.
| What you wrote | Legal JSON? | What the parser calls it | The fix |
|---|---|---|---|
| A // or /* */ comment | No | Expected property name or '}' | Remove it, or use JSONC if the reader supports it |
| Trailing comma in an object | No | Expected double-quoted property name | Delete the last comma |
| Trailing comma in an array | No | Unexpected token ']' | Delete the last comma |
| Single-quoted string | No | Expected property name or '}' | Use double quotes everywhere |
| Unquoted key {a: 1} | No | Expected property name or '}' | Quote every key |
| NaN or Infinity | No | Unexpected token 'N' or 'I' | Send null, or a string, and decide at the receiver |
| Leading zero, as in 01 | No | Unexpected number | Write 1, or quote it if it is a code |
| .5 or 5. as a number | No | Unterminated fractional number | Write 0.5 and 5.0 |
| A raw newline inside a string | No | Bad control character in string literal | Escape it as backslash n |
| Duplicate keys | Yes | nothing at all, it parses | Nothing to fix, but the last value silently wins |
| Integer above 2^53 − 1 | Yes | nothing at all, it parses | Have the API send it as a string |
What JSON forbids that JavaScript allows
JSON started as a subset of JavaScript and stayed small on purpose. The grammar fits on one page, which is why there is a parser for it in every language. Everything convenient that JavaScript added afterwards, and everything a developer reaches for out of habit, is outside that grammar.
“JSON is a lightweight, text-based, language-independent syntax for defining data interchange formats.”
- No comments of either kind, which is the most common complaint about the format.
- No trailing comma after the last element of an array or the last member of an object.
- Strings use double quotes only, and every key must be quoted.
- No NaN, no Infinity, no undefined, and no leading zero on a number.
- A number needs a digit on both sides of the point, so .5 and 5. are both invalid.
The formats that relax those rules are real but separate. JSONC adds comments and is what editors use for configuration files. JSON5 adds comments, trailing commas, unquoted keys, single-quoted strings and hexadecimal numbers. Neither is JSON, and a strict parser at the other end of an API will reject both without apology.
The practical rule is to know which one you are writing. A configuration file your own tooling reads can be JSONC. Anything crossing a network boundary should be plain JSON, because you do not control the parser on the other side and the tolerant behaviour you are relying on is not in the specification.
The two failures that do not raise an error
A syntax error is the easy case, because something tells you. The two problems worth learning are the ones where the parser succeeds, hands you a value, and never mentions that the value is not what the sender wrote.
- Duplicate key {"a":1,"a":2}
- parses, and the result is {"a":2}
- What the specification says
- behaviour is not defined, so parsers differ
- Integer 9007199254740993
- parses as 9007199254740992
- Safe whole number ceiling
- 9,007,199,254,740,991, which is 2^53 − 1
Both are legal documents. Neither raises an error anywhere. The duplicate key count on this page collapses along with the parser, so a key count lower than you expected is itself a hint that duplicates were present.
Duplicate keys matter most where documents are merged or generated by templating, because that is where the same key gets emitted twice without anyone intending it. RFC 8259 calls the behaviour undefined and warns that implementations differ, so a payload that works against one server can behave differently against another.
The number problem is bigger and more common. Database identifiers, snowflake IDs and timestamps in nanoseconds all routinely exceed 2^53 − 1, and every one of them loses its last digits in a JavaScript parser. The only real fix is at the source: send the value as a string and parse it deliberately.
Carrying binary through a JSON field
JSON has no byte type, so a file or a key inside a payload has to travel as text. Base64 is the usual answer, and the size cost is worth checking first.
Open the Base64 encoder →Full guide
Putting JSON in a URL: Validate, Minify, Percent-Encode, or Base64url?
A decision guide for flattening, encoding, checking, and safely transporting JSON in a query string.
Read the full guide →The formula, worked line by line
There is no arithmetic in formatting, only counting, so the definitions matter more than any calculation. Depth, keys and size are the three figures this page reports, and each of them is defined below exactly as the tool computes it rather than as a rule of thumb.
The error location is the one genuine computation. A parser reports a character offset into the document, which is useless to a person reading 400 lines. Turning that offset into a line and a column is a matter of counting the newlines before it, and that is the whole trick.
depth = deepest nesting of arrays and objects, a plain value is 0
keys = every object key at every level, after duplicates collapse
bytes saved = input bytes − minified bytes
error line = 1 + the number of newlines before the offending character
error column = offset − start of that line + 1- Minified
- 166 bytes
- Indented with a tab
- 213 bytes, 22.1 percent larger
- Indented with 2 spaces
- 237 bytes, 30.0 percent larger
- Indented with 4 spaces
- 285 bytes, 41.8 percent larger
- Depth and keys
- 3 levels, 8 keys
The same 8 keys across 3 objects and 1 array. All four versions parse to exactly the same value, which is the point: indentation is for the reader and carries no meaning at all.
Depth counts containers, not values. A single number is depth 0, an empty object is depth 1, and an object holding an object holding an object is depth 3. That last one is the sample above, whose limits object contains a depth object, and it is why the figure is a useful proxy for how awkward a payload will be to consume.
Byte counts here are UTF-8 bytes rather than characters, because that is what a network and a size limit actually measure. A document full of non-Latin text is larger than its character count suggests, and an emoji in a string is four bytes even though it looks like one character on screen.
Minification saves whitespace and nothing else, so its value depends entirely on whether the response is compressed. Over a gzipped or Brotli connection the saving shrinks to very little, because repeated runs of spaces are exactly what a compressor removes best. Uncompressed, in a log line or an embedded string, the figures above are the real ones.
Questions people ask
Sources
Where the constants and formulas on this page come from. Each line names the figure it backs.
Behaviour is unpredictable when object names are not unique, and integers outside plus or minus 2 to the 53rd are not interoperable across implementations.
RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format — IETF, 2017
The JSON syntax itself, defined independently of any programming language.
ECMA-404: The JSON data interchange syntax, 2nd edition — Ecma International, 2017
Related guides
Putting JSON in a URL: Validate, Minify, Percent-Encode, or Base64url?
A decision guide for flattening, encoding, checking, and safely transporting JSON in a query string.
August 11, 2026 · 9 min read
How Many Grams in a Cup? Every Ingredient, One Chart
One formula, fourteen densities. Why flour is 120 g, honey is 340 g, and the ingredient — not the cup — decides the number.
August 10, 2026 · 14 min read
How Are Loan Payments Calculated? Amortization, Explained
One level payment, front-loaded interest — the formula worked by hand, the two levers you control, and why the smaller payment is often the costlier loan.
July 23, 2026 · 13 min read