JSON Formatter
A json formatter that never runs your document through JSON.parse — so it can tell you about the duplicate key and the oversized number instead of quietly deleting them both.
Free · No signup · Nothing leaves your browser
Formats, minifies and checks JSON in your browser. It does not run your document through JSON.parse, so a key written twice is still there afterwards and a number too big for a double keeps its digits — the two things every other formatter loses without telling you.
Valid JSON
Every string is double-quoted, every number matches the JSON grammar, and there is exactly one value in the document.
A key is written twice
- 1
portappears 2 times on line 1 in$Anything that parses this keeps
3000and throws away8080. Both are kept in the output below so you can decide which one you meant.
RFC 8259 says names should be unique and leaves the behaviour undefined when they are not, so parsers disagree. JavaScript, Python and jq keep the last one. Some Go and Rust decoders reject the document outright.
A number will change when this is parsed
- 1
$.tweet_id1234567890123456789 1234567890123456800 ← after JSON.parse
Larger than 9,007,199,254,740,991, the biggest integer a double holds exactly. Database IDs, Snowflake IDs and int64 counters land here constantly — the fix is to send it as a string.
The output below still carries the original digits, because this page never reparses your numbers. A formatter built on JSON.parse would have written the second line back out as if it were what you pasted.
Everything runs in your browser — the document is never uploaded, logged or stored. JSON is where access tokens, customer records and API responses live, which is a good reason not to paste it into someone else's server just to add indentation.
Tekk is a spec-driven development platform for people building software with AI coding agents — for the bugs that survive because nothing was looking for them.
What the round trip deletes
Almost every online JSON tool is the same three words underneath:
JSON.stringify(JSON.parse(input), null, 2)
It works, it is fast, and it loses two things on the way through — both silently, and both exactly the kind of thing you opened a formatter to find.
1. A key written twice
{
"service": "checkout",
"port": 8080,
"port": 3000
}
This is not a syntax error. RFC 8259 says names should be unique and leaves the behaviour undefined when they are not, which means parsers are free to disagree — and they do. JavaScript, Python and jq keep the last one. Some Go and Rust decoders reject the document. A strict JSON Schema validator may or may not see it at all.
So 8080 is gone, nothing said anything, and the formatter that was supposed to show you the problem is the thing that deleted it.
This page keeps both, tells you which line each is on, and tells you which one a parser would have kept.
2. A number bigger than a double
{ "tweet_id": 1234567890123456789 }
Run that through JSON.parse and back out:
{ "tweet_id": 1234567890123456800 }
The last three digits are different. JSON.parse puts every number into an IEEE 754 double, which holds integers exactly only up to 9,007,199,254,740,991 — and 19-digit IDs are ordinary now. Snowflake IDs, int64 primary keys, Discord and Twitter object IDs, monetary values in minor units on a large ledger.
Nothing throws. The JSON still looks like JSON. The ID is simply wrong, and stays wrong, and this is why APIs that use large integers send them as strings.
This page keeps the source text of every number and never reparses it, so the output carries the digits you pasted. The panel tells you which values would not survive somebody else's parser.
Errors, with somewhere to look
| Error | What it usually means |
|---|---|
| Trailing comma | Legal in JavaScript and JSON5, never in JSON. The most common reason a hand-edited file stops parsing. |
| Comment | The file is JSONC — normal for tsconfig.json and .vscode/settings.json, rejected by JSON.parse. |
| Single-quoted string | A JavaScript object literal or a Python dict, not JSON. |
| Unquoted key | Same. JSON requires every key to be a double-quoted string. |
True / False / None |
Python. This came from print() on a dict rather than json.dumps(). |
NaN / Infinity |
JSON has no way to write either. Serialisers usually emit null. |
| Leading zero on a number | Not valid JSON. If it is a zip code or an ID it belongs in a string — the leading zero is lost otherwise. |
| String is never closed | A raw line break inside a string. Write \n instead. |
Each one is reported with a line, a column and the source line it happened on — and the document is converted anyway, so you get strict JSON out of a file that would not parse.
JSON Lines is not broken JSON
{"level":"info","msg":"started"}
{"level":"warn","msg":"retrying"}
This is NDJSON — one document per line, no wrapping array, no commas. It is what log pipelines, bulk import APIs and streaming endpoints emit, and it is not a mistake. A formatter that reports "unexpected token on line 2" sends you looking for a syntax error that does not exist, so this page checks whether every line parses on its own and says what it is actually looking at.
What it does not do
It checks that the document is well-formed JSON. It does not validate against a JSON Schema — that needs the schema, and this page never asks you to supply one.
It also does not sort your keys, collapse your arrays, or normalise your unicode into \u escapes. Those are all defensible choices in a linter and all wrong in a formatter, where the only safe assumption is that everything except the whitespace was deliberate.
How it works
- 1
Paste it and read the verdict
It formats as you type, with no submit button and no upload. If the document does not parse, this json formatter gives you the line, the column, the offending source line and the likely cause — not the word "invalid" that most online tools return.
- 2
Check the duplicate-key panel
A key written twice is not a syntax error, so nothing rejects it. JavaScript, Python and jq keep the last one and throw the first away. You get both, with the line numbers, and both survive into the output so you can decide which one you meant.
- 3
Check the number panel
Any number with more digits than a double holds is listed with what it becomes after parsing. Snowflake IDs, int64 counters and database keys land here constantly, and the corruption is invisible because the JSON still looks fine.
Frequently asked questions
- Do you store or upload my JSON?
- No. The parser is a few kilobytes of JavaScript that runs on your machine — there is no server call, nothing is logged and there is no account. JSON is where access tokens, customer records and API responses live, which is a good reason not to paste it into someone else's server just to add indentation.
- What does this do that other JSON formatters do not?
- It does not use JSON.parse. Almost every online formatter is JSON.stringify(JSON.parse(input), null, 2) underneath, and that round trip destroys two things before it can report them: a key written twice, and the digits of any number too large for a double. This page lexes and parses the text itself and keeps the source of every value, so both survive to be shown to you.
- Why does it warn about a duplicate key when my file works fine?
- Because it works fine by accident. RFC 8259 says object names SHOULD be unique and leaves the behaviour undefined when they are not, so parsers disagree: JavaScript, Python and jq keep the last occurrence, while some Go and Rust decoders reject the document outright. A config file with a setting written twice is silently using one of them, and the other one is the change you thought you made.
- Why would a number change when it is parsed?
- JSON.parse puts every number into an IEEE 754 double, which holds integers exactly only up to 9,007,199,254,740,991. A 19-digit Snowflake ID comes back with different digits at the end. Nothing errors, nothing warns, and the value is simply wrong from then on — which is why APIs that use large IDs send them as strings.
- Why will my JSON not parse?
- In order of how often it actually happens: a trailing comma before a closing brace, a comment, single quotes instead of double, an unquoted key, and a raw line break inside a string. All five are legal JavaScript and none are legal JSON. Rather than stopping at the first one, this page names each occurrence with its position and converts the document anyway.
- Can it handle comments, like in tsconfig.json?
- Yes. Files like tsconfig.json and .vscode/settings.json are JSONC, not JSON — they carry comments that JSON.parse rejects. Paste one in and the comments are stripped, reported, and the output is strict JSON you can feed to anything.
- Can I paste a Python dict or a JavaScript object?
- Yes, and this is the most common thing people are actually holding. True, False and None become true, false and null; single quotes become double; unquoted keys get quoted; NaN and Infinity become null, since JSON cannot express them. Everything it changed is listed, so nothing happens silently.
- Does it work as a json beautifier for minified API responses?
- That is the main use. Paste a single-line response from curl or a browser network tab, pick 2, 4 or 8 spaces, and read it. As a json beautifier it is also the fastest way to find out whether the payload you were sent is the payload you expected.
- Is there a json minifier as well?
- Yes — the minify toggle strips every byte of insignificant whitespace and returns the document on one line. The json minifier keeps strings untouched, because whitespace inside a string is data and removing it would change the value.
- Is this a json validator too?
- For syntax, yes. A json validator in this sense answers whether the document is well-formed JSON, and this page does that with the exact position of anything that is not. It does not validate against a JSON Schema — that needs the schema, and this page never asks you for one. Any tool that claims to validate without one is checking syntax and using a bigger word.
- My log file will not parse. What is JSON Lines?
- It is one JSON document per line, with no wrapping array and no commas — what most log pipelines and bulk APIs emit. A formatter that reports a syntax error on line 2 sends you hunting for a mistake that is not there, so this page checks for it and says so instead.
- Will formatting change my document?
- Only whitespace between values, which JSON treats as insignificant. Keys stay in the order you wrote them, escape sequences are copied byte for byte, unicode is left as unicode rather than escaped, and numbers are never reparsed. Formatting twice gives the same result as formatting once.
- Is there a size limit?
- No hard cap, but it re-parses on every keystroke, so a multi-megabyte document will feel sluggish in the textarea. For files that large, paste a representative section rather than the whole thing.
- Why is this free, and what is Tekk?
- Tekk is a spec-driven development platform for people building software with AI coding agents. This page costs nothing to run because nothing runs on our servers, so there is no signup wall, no run limit and no upsell inside the tool.
Want a real spec for what you’re building?
Drop a sentence. Tekk grounds it in your actual code and turns it into an executable plan.
Free to try · Connect GitHub during signup