A JSON formatter takes JSON that has been squashed onto one line, or indented by someone in a hurry, and lays it out so you can read it. It also checks it, which is often the real reason you came.
{
"id": 9007199254740993,
"name": "Miso",
"age": 3,
"toys": [
"mouse",
"ball"
],
"vet": {
"next": "2026-10-01",
"done": false
}
}Valid JSON. 110 bytes in, 159 bytes out. Nothing here leaves your browser.
Type or paste in the left box and it updates as you go. The result is colour
coded, with keys, strings, numbers and true, false and null each in their
own colour, so the structure is visible at a glance. Delete a closing bracket,
or leave a comma after the last item, and the tool points at the exact line and
column and says what is wrong. Press Minify to go the other way,
Sort keys to put every object's keys in alphabetical order, and pick the
indent that matches the rest of your project.
What counts as valid JSON
JSON is smaller than most people remember. If something is failing, it is almost always one of these.
| Mistake | Broken | Fixed |
|---|---|---|
| Trailing comma | [1, 2,] | [1, 2] |
| Missing comma | {"a": 1 "b": 2} | {"a": 1, "b": 2} |
| Single quotes | {'a': 1} | {"a": 1} |
| Unquoted key | {a: 1} | {"a": 1} |
| Comment | {"a": 1 // note} | remove it |
undefined or NaN | [undefined] | [null] |
Python's True and None | [True, None] | [true, null] |
| Leading zero | [007] | [7] |
| Curly quotes | {“a”: 1} | {"a": 1} |
| Raw line break in a string | a newline inside the quotes | write it as \n |
The curly quotes deserve a mention. They arrive from word processors and chat apps, they look identical to the straight ones, and no amount of staring at the text will find them. The tool does.
The six JSON types
Everything in a JSON document is one of six things.
| Type | Example | Rules |
|---|---|---|
| String | "meow" | Double quotes only. Escape ", \ and control characters. |
| Number | -12.5e3 | Decimal only. No NaN, no Infinity, no hex, no leading + or leading zeros. |
| Boolean | true, false | Lowercase. |
| Null | null | Lowercase. The only way to say "nothing". |
| Array | [1, "two", null] | Ordered. Values can be of mixed types. |
| Object | {"key": "value"} | Keys are strings in double quotes. Order is not meaningful to the format. |
A whole document is a single value, and any of the six is allowed at the top
level. 42 on its own is valid JSON.
Format or minify
The two are the same data with different whitespace.
| Format | Minify | |
|---|---|---|
| Whitespace | Line breaks and indentation | None at all |
| Reads well | Yes | No |
| Size | Larger | Smallest |
| Use it for | Reading, diffing, code review | Storing, sending, embedding in a URL or a string |
Minifying saves the most on deeply nested data with short values, and least on long strings, which it cannot touch. Servers that compress responses recover most of the difference anyway, so minified JSON matters mainly where nothing compresses it.
Choosing an indent
Two spaces is the common choice in JavaScript projects, and it is what npm
writes package.json with. Four spaces is a habit in Python, where
json.dumps(data, indent=4) is the usual call. A tab lets each reader set the
width in their own editor. There is no correct answer, only matching the files
around it, so a diff shows changes and not re-indentation.
What it does not change
Most online formatters parse the JSON into a JavaScript value and print it again. That is the shortest way to write one, and it quietly edits your data. This one keeps the text of every string and number exactly as you wrote it.
| You paste | Parse then print gives | This tool gives |
|---|---|---|
9007199254740993 | 9007199254740992 | 9007199254740993 |
[1.0, 1E2, -0] | [1,100,0] | [1.0, 1E2, -0] |
{"a": 1, "a": 2} | {"a":2} | both, with a warning |
{"b": 1, "2": 2, "1": 3} | {"1":3,"2":2,"b":1} | b, 2, 1 in that order |
"é" | "é" | "é" |
The first row is the one that bites. A JavaScript number is a 64-bit float, and it cannot hold every whole number above 253. Database IDs and timestamps in nanoseconds regularly go past that, and a formatter that changes an ID while making it easier to read is worse than none.
The duplicate keys row is the other one worth knowing. The JSON specification says names within an object should be unique, and leaves what a parser does with duplicates up to the parser. JavaScript keeps the last and drops the rest without saying so, which hides exactly the mistake you may have pasted the document in to find. Here every copy stays in the output and the tool tells you which keys were repeated and on which line.
How it works
- Read the text one character at a time, following the grammar in RFC 8259 and nothing looser.
- Build a tree of arrays, objects and values, keeping the original text of every string and number.
- If a character breaks the grammar, stop and report its line and column, plus the mistake it most likely is.
- Otherwise print the tree, adding a line break and an indent after every opening bracket and comma, or nothing at all when minifying.
Because the parser knows what it was in the middle of when it stopped, it can
say more than a bare "unexpected token". Running out of input names the array
or object that was never closed and where it started. A } where a ] should
be points back at the bracket it failed to match.
When to use it
| Reach for it when | Reach for something else when |
|---|---|
| An API response or a log line is one unreadable line | The file is tens of megabytes: use jq on the command line |
| A config file will not load and you need to know where it breaks | The file has comments on purpose: it is JSONC or JSON5, not JSON |
| You want to check a payload before sending it | You need to query or transform the data: that is a job for jq or code |
| You need it minified for a request body or an environment variable | You want it smaller over the wire: turn on compression at the server |
| Two documents need the same shape before a diff | The data is sensitive and you cannot trust a webpage: this one runs locally, but use a command-line tool if the rules say so |
Common questions
Why does my JSON say Unexpected token?
Something in the text is not allowed by the JSON grammar, and the parser gave up at the first character that broke the rules. Read the line and column above the box, then look at that character and the one just before it. The usual causes are a trailing comma, a missing comma between two values, single quotes instead of double quotes, a property name with no quotes, and a comment. This tool names which one it found.
Is JSON the same as a JavaScript object?
No. JSON is a text format, and a JavaScript object literal is code. Object literals allow unquoted keys, single quotes, trailing commas, comments, undefined and functions, and JSON allows none of them. Every JSON document happens to be valid JavaScript, but plenty of valid JavaScript objects are not valid JSON, which is why pasting one into a JSON parser fails.
Does formatting change my data?
No. Formatting only adds or removes whitespace between values. Numbers and strings are copied exactly as you wrote them, keys stay in the order you wrote them unless you press Sort keys, and duplicate keys are kept and flagged rather than dropped. That is not true of every formatter: anything that parses to a JavaScript value and prints it again will round large numbers and reorder some keys.
Why do comments and trailing commas break JSON?
The JSON grammar, RFC 8259, has neither, so a strict parser rejects them. Some tools accept them anyway. JSONC, which VS Code uses for its settings, and JSON5 are supersets of JSON that add comments and trailing commas, but they are different formats. If a file needs to be real JSON, remove them.
Is anything I paste here sent to a server?
No. The formatting runs in your browser and neither box is submitted anywhere. The site records that the tool was used, which action and indent were chosen, how many characters were involved and whether the JSON was valid, so we know which tools are worth building next. The text itself is never part of that.
How large a file can it handle?
The parsing is quick: about 4 MB formats in under a tenth of a second in our tests. The text boxes are the limit, not the parser. It re-formats on every keystroke, so past a few tens of megabytes typing gets sluggish, and a command-line tool such as jq is the better fit. The colour coding switches off above 100,000 characters of output, because every coloured value is a separate element on the page; the text and the Copy button are unaffected. Nesting is capped at 512 levels, which is far deeper than real data goes.