Skip to content
ansezz.

▸ Free tool

JSON Formatter & Validator.

Format, minify and validate JSON — and when it breaks, get the line, the column, a caret under the offending character, and a straight answer about what to fix. Nothing leaves your browser.

▸ Strict on purpose

This validates against RFC 8259 — no comments, no trailing commas, no single quotes. If your file needs those, it is JSONC or JSON5, not JSON.

Try

Runs in this tab · nothing is uploaded · validation is live under 2 MB

Paste JSON above to validate it.

▸ Document stats

Input
Output
Minified
Saved by minify
Keys
Max depth
Objects
Arrays

    The error message is the whole product

    Formatting JSON is a one-liner — JSON.stringify(JSON.parse(text), null, 2). What actually costs you time is a 4,000-line payload that will not parse and an engine that says Unexpected token and nothing else. Every engine words it differently: V8 gives you a byte offset, SpiderMonkey gives you a line and column, JavaScriptCore usually gives you neither.

    So this tool does not lean on the engine. It runs its own scanner over the document first, stops at the first thing the grammar forbids, and reports the line, the column, the surrounding lines, a caret under the exact character, and what to change. Trailing comma, single quotes, unquoted key, missing comma, stray BOM, NaN, a Python repr that was printed instead of serialized — each one gets its own explanation instead of a generic parse failure. JSON.parse still does the real decoding afterwards; the scanner exists so the failure is legible.

    One honest limit: a browser textarea is the wrong place for a very large file. Live validation switches off above 2 MB and the buttons take over. Past a few megabytes, jq or python -m json.tool will be faster and will not fight your scroll position.

    JSON vs JSONC vs JSON5

    Most "invalid JSON" is valid something-else. Comments are the clearest case: tsconfig.json, .eslintrc.json and VS Code's settings all carry // lines, and they all parse — because the tools reading them use a JSONC parser, not JSON.parse. The file extension lies.

      JSON (RFC 8259) JSONC JSON5
    Comments
    Trailing commas usually tolerated
    Unquoted keys
    Single-quoted strings
    NaN / Infinity
    Hex numbers, leading +
    JSON.parse accepts it
    Where you meet it APIs, webhooks, config, logs tsconfig.json, VS Code settings, .eslintrc hand-edited config files

    The rule of thumb: if a human edits the file, a dialect with comments is a kindness. If a machine sends it over a wire or stores it in a column, stay on strict JSON, because you do not control which parser is at the other end.

    Minifying matters less than compression

    Pretty-printing a document with 2-space indent typically adds 10–20% to its size, and the stats bar above shows you exactly how much. Then gzip or brotli comes along and eats almost all of it, because indentation is the most compressible thing in the file — a long run of identical bytes. Minifying a response that is already served with Content-Encoding: gzip usually moves the transferred size by a couple of percent.

    Minifying does pay where compression is not in the path: values written into localStorage or IndexedDB against a quota, queue payloads bumping a size ceiling (SQS caps a message at 256 KB), JSON stuffed into a database column, cached blobs in Redis, and prompts sent to an LLM — where whitespace is billed as tokens, which you can measure with the token counter. Turn compression on first. Then argue about whitespace.

    Key order is not data

    RFC 8259 says an object is an unordered collection of name/value pairs. Most parsers preserve insertion order anyway, which teaches people to rely on it — right up until JavaScript does not. Any object key that looks like an array index is hoisted to the front in ascending numeric order, so {"10":"a","2":"b"} re-serializes as {"2":"b","10":"a"}. That is the language specification, not a bug in this tool, and the stats bar flags documents where it can bite.

    Sorting keys is still useful — for diffs that stop churning, for cache keys that stay stable, for snapshot tests that stop flapping. The sort here is recursive and compares by code unit rather than localeCompare, so you get the same output on every machine in every locale. What it is not is a canonicalization scheme: if you need a hash or a signature over JSON, either hash the exact bytes you received — which is what every webhook HMAC check does, and why you must never re-serialize before verifying — or use a real canonical form such as JCS (RFC 8785).

    The 253 bug that silently corrupts IDs

    JSON numbers have no integer type. Every one of them lands in an IEEE-754 double, which represents integers exactly only up to Number.MAX_SAFE_INTEGER — 9007199254740991. One past that, JSON.parse('{"id":9007199254740993}') hands you 9007199254740992. No exception, no warning, just a different record. Snowflake IDs from X and Discord, Postgres bigint primary keys, order references and ledger amounts in minor units all live in that range, which is exactly why mature APIs ship them as strings.

    This tool scans the raw text for integer literals and reports every one that fails to round-trip, with the value you will actually get back — paste the "Big ID" sample and watch. Newer V8 can hand a JSON.parse reviver the untouched source text (with JSON.rawJSON for the trip back out), but support is not universal yet. The portable fix has not changed: serialize big identifiers as strings, and never let one make a round trip through a JavaScript number.

    Duplicate keys, and NDJSON for logs

    RFC 8259 says names within an object should be unique — should, not must. So parsers improvise. JavaScript and Python keep the last occurrence, some libraries keep the first, a few return both. When a proxy validates a request with one parser and the backend reads it with another, that disagreement becomes a real attack: {"role":"user","role":"admin"} passes the check and lands as something else. The stats bar names every duplicate key and the line it is on.

    The other thing people paste in here is not one document at all. Logs, exports and streaming APIs usually emit NDJSON — one complete JSON value per line, no wrapping array, no commas between records. It appends cheaply, it survives truncation (you lose the last line, not the file), and it streams line by line instead of forcing a reader to hold the whole array in memory, which is the same argument as structured logging in logging vs monitoring. A strict parser rejects it, correctly. When this tool sees a second top-level value it says so instead of pointing at a random bracket — split on newlines and parse each line on its own.

    Questions, answered

    Why doesn't JSON.parse tell me which line the error is on?

    Because the message is not standardised. V8 (Chrome, Node, Edge) appends "at position 42 (line 3 column 5)", SpiderMonkey (Firefox) says "at line 3 column 5 of the JSON data", and JavaScriptCore (Safari) often gives you a bare "JSON Parse error: Expected '}'" with no position at all. This tool does not rely on any of that: it scans the document itself, so you always get the line, the column, a caret under the exact character, and a plain explanation of what is wrong.

    Are trailing commas allowed in JSON?

    No. RFC 8259 has no trailing commas anywhere — not after the last array element, not after the last object member. JavaScript, JSON5 and most JSONC parsers accept them, which is why they show up constantly in files copied out of an editor. Delete the comma before the closing bracket and the document parses.

    Does minifying JSON make my API faster?

    Barely, if you have gzip or brotli switched on — compression already collapses repeated whitespace, so stripping it usually buys a few percent of the compressed payload. Minifying pays where compression does not run: browser storage quotas, queue message size limits, database columns, Redis memory, and LLM prompts where every space is billed as a token. Turn on compression first, then worry about whitespace.

    Why did my large ID change after JSON.parse?

    JSON numbers become IEEE-754 doubles, which hold integers exactly only up to 2^53 - 1 (9007199254740991). Anything larger is rounded to the nearest representable value with no error and no warning: 9007199254740993 comes back as 9007199254740992. Snowflake IDs, Postgres bigint keys and payment references all land in that range, which is why serious APIs send them as strings. This tool flags every integer in your document that fails to round-trip.

    Is my JSON uploaded anywhere?

    No. The scanner, JSON.parse, the formatter and the key sort all run in this tab — there is no request, no logging and no server involved. Open your network tab while you paste, or load the page once and switch off your network. That matters here more than on most tools: the fastest way to leak a production payload is to paste it into a formatter that posts it to a backend.

    Can this tool handle comments in JSON, like tsconfig.json?

    It detects them and tells you exactly where they are, but it will not parse them, because // and /* */ are JSONC, not JSON. tsconfig.json, .eslintrc and VS Code settings are read by JSONC-aware parsers; JSON.parse rejects all three. If you need to keep the comments, use a JSONC reader such as jsonc-parser or json5; if you need to ship the file over the wire, strip them.

    Keep reading