JSON Formatter and Validator
Pretty-print, minify or browse JSON as a collapsible tree, 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"
]
}Tree
{ 4 keys }
limits: { 2 keys }
depth: { 2 keys }
tags: [ 3 items ]
- 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.
Advertisement
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. Under it the same document is drawn as a collapsible tree, so a payload too long to scroll can be opened branch by branch. The panel then reports the nesting depth, the number of keys, how many objects and arrays there are, the minified size, and the bytes minifying would save.
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
Advertisement
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 →Advertisement
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.
Advertisement
Questions people ask
Why can I not put comments in JSON?
Because the grammar has no rule for them. Douglas Crockford removed comments from the format deliberately, on the grounds that people were using them to carry parsing directives and breaking interoperability. The result is that both // and the slash star form are syntax errors in every strict parser, and this page will point at the first slash. If you need comments in a configuration file, use JSONC, which most editors read, or JSON5. If the file crosses a network boundary, keep it plain and put the explanation in a documented field or somewhere else entirely.
Covered in depth in Putting JSON in a URL: Validate, Minify, Percent-Encode, or Base64url? →
Are duplicate keys an error in JSON?
No, and that is exactly what makes them dangerous. A document such as the one with an a key set to 1 and then to 2 parses without complaint, and JavaScript hands you the last value, so the 1 disappears. RFC 8259 says the behaviour of a parser receiving duplicate names is unpredictable and that implementations differ, so another language might give you the first value or an error instead. Because the winning key collapses before this page counts anything, a key count lower than you expected is often the first sign that duplicates are present.
Why did my large ID number change after parsing?
Because JavaScript numbers are IEEE 754 doubles, which represent whole numbers exactly only up to 9,007,199,254,740,991, that is 2 to the power 53 minus 1. Anything larger is rounded to the nearest representable value the instant it is parsed: 9007199254740993 becomes 9007199254740992. JSON itself sets no limit on number size, so the document is perfectly valid and nothing raises an error. This page counts such values and warns you, but the original digits are already gone. The only real fix is for the sender to emit large identifiers as strings.
Does minifying JSON actually make a difference?
It depends on whether the payload is compressed. The sample document on this page is 166 bytes minified and 237 bytes at two-space indentation, so minifying removes 30 percent, rising to 41.8 percent against four-space indentation. Those are real savings for anything uncompressed, such as a value stored in a database column, embedded in a log line or held in a size-capped message. Over a gzipped or Brotli connection the gap narrows sharply, because runs of repeated spaces are the easiest thing in the world for a compressor to remove.
Is my JSON uploaded anywhere when I paste it here?
No. Parsing, formatting, sorting and measuring all run in your browser on this page. Nothing is sent to a server, nothing is logged, nothing is stored between visits, and the document is never written into the page URL, so there is no shareable link quietly carrying it around. That matters because the thing people most often paste into a JSON formatter is a real API response, which usually contains real customer records, real tokens, or both. Close the tab and it is gone.
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
Utilities
How Long Should a Password Be?
Eight characters with every symbol you can find: 5 hours. Twelve lowercase letters and nothing else: 6 days.
August 15, 2026 · 10 min read
Utilities
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
Dates & Time
Time and a Half: The Regular Rate Is Not Your Hourly Wage
Every explanation says multiply your hourly rate by 1.5. That is the wrong number the moment a bonus, a shift differential, or a second pay rate enters the week.
August 30, 2026 · 8 min read