JSON Formatter
Format, minify and validate JSON in your browser. Big numbers like 1830000000000000001 stay exact, duplicate keys are flagged, and JSONC comments convert.
- Runs in your browser
- Your data never leaves your browser
- Free · No Sign-Up
Scan with WeChat to share this tool
Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.
What Formatting Keeps and What It Rewrites
The formatter reads the text with its own parser, written to RFC 8259 and tested against all 318 files of JSONTestSuite: it accepts the same documents as JSON.parse. It differs from a JSON.parse + JSON.stringify round trip in three places:
- Numbers are copied as written.
1.0,0.10,1e2and12345678901234567890come out unchanged. - Duplicate keys are kept. RFC 8259 §4 says names SHOULD be unique and that parsers handle duplicates in different ways; this tool keeps every copy and tells you where they are.
- A byte order mark is removed and reported.
JSON.parserejects a leading U+FEFF; RFC 8259 §8.1 lets a parser ignore it.
Whitespace and string escapes are rewritten. Strings are written the way JSON.stringify writes them, so "\u00e9" becomes "é" and "\/" becomes "/". Turn on Escape non-ASCII to write every character above U+007E as \uXXXX, as python3 -m json.tool does by default.
Example: An Order ID Longer Than 16 Digits
{"order_id":1830000000000000001,"total":19.90,"currency":"USD","items":[{"sku":"A-100","qty":2,"price":9.95}],"paid":true,"coupon":null}
Output with 2 spaces:
{
"order_id": 1830000000000000001,
"total": 19.90,
"currency": "USD",
"items": [
{
"sku": "A-100",
"qty": 2,
"price": 9.95
}
],
"paid": true,
"coupon": null
}
A note lists 1830000000000000001 → 1830000000000000000 at /order_id: that is what JSON.parse returns. RFC 8259 §6 explains why: software that reads numbers as IEEE 754 doubles only exchanges integers between −(2^53 − 1) and 2^53 − 1 reliably. If a browser will read the field, send it as a string.
Set Numbers to As JavaScript reads them to see what a script gets:
[1.0, 1e2, 0.10, -0, 1e400]
Kept as written (minified):
[1.0,1e2,0.10,-0,1e400]
[1.0, 1e2, 0.10, -0, 1e400]
As JavaScript reads them:
[1,100,0.1,0,1e400]
1e400 overflows a double: JSON.parse returns Infinity and JSON.stringify writes null, so the tool keeps the literal and says so.
Example: Duplicate Keys
{"retry": 3, "timeout": 30, "retry": 5}
With Duplicate keys set to Keep all, both entries stay and the note points at the second retry:
{"retry":3,"timeout":30,"retry":5}
{"retry": 3, "timeout": 30, "retry": 5}
With Keep the last, the output matches JSON.parse, jq and Python: the last value at the first position.
{"retry":5,"timeout":30}
Error Messages
The status line names the cause in plain words, and the output panel shows the line before, the line with the error, and a caret:
{
"name": "api",
"port": 8080,
}
Status: “Line 3, column 15: trailing comma before the closing bracket”.
2 | "name": "api",
3 | "port": 8080,
| ^
| Input | Message |
|---|---|
{"a":1} // note | comments are not allowed in JSON |
{'a': 1} | JSON strings and property names need double quotes (“) |
{a: 1} | property names must be in double quotes |
{"ok": True} | unknown word; JSON only has true, false and null, plus a note that True is Python and JSON writes it as true |
[01] | invalid number (no leading zeros, ”+”, “.5”, NaN or Infinity in JSON) |
{"a":“b”} | curly quotes (“) are not JSON quotes; use straight double quotes (”) |
Near-JSON gets a one-click fix: JSON inside a Markdown code fence (common in chatbot answers), JSON escaped as a string ({\"a\":1}, common in logs), and one string holding JSON. JSON Lines input gets a link to the JSONL Converter.
Comments: JSONC and JSON5
VS Code’s settings.json, tasks.json and launch.json use JSON with Comments: // and /* */ comments, and trailing commas, which VS Code accepts with a warning. Plain JSON rejects both. With Accept JSON5 / JSONC on, the tool reads JSON5 (a superset of JSONC) and writes JSON:
{
// Editor
"editor.tabSize": 2,
"files.exclude": {
"**/.git": true,
},
}
Output, with the note “Changed to make it JSON: 1 comment removed, 2 trailing commas”:
{
"editor.tabSize": 2,
"files.exclude": {
"**/.git": true
}
}
Hex numbers become decimal (0x1F90 → 8080, exact at any size), .5 becomes 0.5, and single quotes become double quotes. On 103 test inputs the result matches the json5 2.2.3 package, except NaN and Infinity, which JSON cannot store.
Sorting Keys and Matching jq or Python
Sort keys orders keys by Unicode code point at every level, the same order as jq -S and python3 -m json.tool --sort-keys. With 4 spaces and Escape non-ASCII on, the output is byte-for-byte what Python 3.12’s json.tool prints for integer data:
{"name":"Zoë","city":"Kraków","age":30}
Output:
{
"age": 30,
"city": "Krak\u00f3w",
"name": "Zo\u00eb"
}
Where the three differ on numbers: jq 1.7.1 keeps literals but rewrites exponents (1e2 → 1E+2); Python turns 1e2 into 100.0 and 1e400 into Infinity, which is not valid JSON; this tool keeps both as written. The test script compares 400 random documents with jq and 120 with Python on every run where those exact versions are installed.
How It Compares
Tested on 2026-10-02 in desktop Chromium with {"id":12345678901234567890,"price":19.90,"big":1e400,"z":-0,"a":1,"a":2}. None of these sites sent the JSON to a server during the test.
| Tool | 19-digit ID | 1e400 | Duplicate a | Trailing comma |
|---|---|---|---|---|
| jsonformatter.org (Format / Beautify) | 12345678901234567000 | null | only "a": 2, no warning | ”Expecting ‘STRING’, got ’}‘“ |
| JSONLint (Sort Keys) | 12345678901234567000, with a W050 warning on Validate | null, no warning | only "a": 2, W060 warning | E008 trailing comma |
| ZeroTool | unchanged, listed in a note | unchanged, listed in a note | both kept, listed in a note | named, with a caret and a JSON5 fix |
JSONLint warns about the integer and the duplicate, yet its Sort Keys output still changes them.
FAQ
Is my JSON sent to a server?
No. Parsing and formatting run in your browser tab. The input is saved in this browser's local storage so it is still there when you come back; Clear removes it.
Why does another formatter turn my 19-digit ID into a different number?
Most online formatters call JSON.parse, which stores every number as a 64-bit double. Integers above 9,007,199,254,740,991 (2^53 − 1) cannot all be stored, so 1830000000000000001 comes back as 1830000000000000000. This formatter keeps the digits you typed and lists the numbers JavaScript would change.
Can it format JSON with comments, like VS Code settings.json?
Yes. Turn on Accept JSON5 / JSONC, or press Convert to JSON when the error appears. Comments are removed and trailing commas, single quotes and unquoted keys are rewritten; a note lists every kind of change. NaN and Infinity stay an error because JSON has no way to write them.
Does formatting change my data?
Values stay the same. Whitespace changes, and string escapes are rewritten the way JSON.stringify writes them: \u00e9 becomes é and \/ becomes /. Numbers and duplicate keys are kept as written unless you choose otherwise.
What is the largest file it handles?
Files up to 50 MB open. Input up to 2 MB is formatted as you type; above that, press Format. Parsing and formatting run in a Web Worker, so the page stays responsive; editing the input, pressing Format again or Clear stops the previous run. In our test (Apple M1 Max, Chromium 152, 2026-10-03) a 10.7 MB file took 2 to 4 seconds to format, and putting that much text into the input box took the browser 1 to 2 seconds.