JSON Formatter & Validator

Format, minify and check JSON, and see the exact line and column where it breaks.

Result
{
  "name": "quackyard",
  "tools": [
    "json formatter",
    "json validator"
  ],
  "since": 2024,
  "stats": {
    "visits": 1e6,
    "paid": null
  }
}

6 keys, nesting 2, 112 bytes in → 157 bytes out

Runs in your browser. Nothing you enter is sent anywhere.

How to use it

Paste JSON into the JSON box. It’s checked as you type, in your browser; nothing is uploaded.

  1. Choose Format to pretty-print, then pick the indent: 2 spaces, 4 spaces or Tab. Choose Minify to remove every space and line break between tokens; the indent choices are disabled there because minified JSON has no indentation.
  2. Tick Sort keys to order the keys of every object, at every depth, by Unicode code point. Arrays keep their order: an array’s order is part of its data.
  3. Press Copy next to Result. The line under the result counts the keys, the deepest nesting and the size in UTF-8 bytes before and after.

If the text isn’t valid JSON, you get one sentence naming the problem and its position, and the broken line is shown with a caret under the column. Repeated keys and a leading byte order mark don’t block the output; each is listed under Warnings.

Examples

A minified API response, with Format and 2 spaces:

{"id":7,"tags":["a","b"],"owner":{"name":"Ada","admin":true}}
{
  "id": 7,
  "tags": [
    "a",
    "b"
  ],
  "owner": {
    "name": "Ada",
    "admin": true
  }
}

The status line reads 5 keys, nesting 2, 61 bytes in → 102 bytes out.

A config file with a trailing comma:

{
  "name": "api",
  "port": 8080,
}

The error is Trailing comma before } at line 3, column 15. The position points at the comma itself, which is the character to delete.

Big and precise numbers, with Minify:

{"price": 1.10, "id": 12345678901234567890, "name": "café"}
{"price":1.10,"id":12345678901234567890,"name":"café"}

Every token comes out as it went in. The same text through JSON.stringify(JSON.parse(text)) gives {"price":1.1,"id":12345678901234567000,"name":"café"}.

A repeated key, with Sort keys on:

{"z":1,"a":{"y":2,"b":3},"a":0}
{
  "a": {
    "b": 3,
    "y": 2
  },
  "a": 0,
  "z": 1
}

Warnings lists Duplicate key "a" at line 1, column 26. Both copies are kept, in their original order, so you can see which one gets overwritten.

Good to know

  • The grammar is RFC 8259, the JSON standard (ECMA-404 defines the same syntax). Comments, trailing commas, single-quoted strings, unquoted keys, leading zeros like 007, a leading + or .5, NaN, Infinity and undefined are all rejected. So is a raw tab or line break inside a string: control characters must be escaped as \t, \n or \u0009.
  • JSONC and JSON5 aren’t JSON. tsconfig.json and VS Code’s settings.json allow comments and trailing commas, so they fail here, correctly: JSON.parse and most APIs would reject them too.
  • Formatting never rounds a number. JSON numbers are arbitrary-length text, but JavaScript reads them as IEEE 754 doubles, which are exact only up to 2^53 − 1 (9007199254740991). This tool writes the original tokens back, so 64-bit IDs keep every digit and 1e400 stays 1e400 instead of becoming null.
  • Duplicate keys are legal but ambiguous. RFC 8259 says names “SHOULD be unique” and leaves the result to the parser; JavaScript, Python and most others keep the last value without a word.
  • One document at a time. Newline-delimited JSON (NDJSON, JSON Lines) holds one value per line, so the second line fails with Unexpected text after the JSON value.
  • A byte order mark at the start is skipped. RFC 8259 section 8.1 lets a parser ignore the invisible U+FEFF some Windows editors write first, so it’s dropped from the result but counted in the bytes in. Anywhere else it fails as Invisible byte order mark (U+FEFF). JSON.parse and Python’s json.loads reject a leading one, so save files as UTF-8 without BOM.
  • Sorting is by code point, not locale: "B" sorts before "a", and "10" before "9".
  • Lines and columns start at 1, and a column counts characters, not bytes. Input is limited to 500,000 characters and 500 levels of nesting.

Questions

How do I check if JSON is valid?

Paste it into the box: valid JSON shows a formatted result, and invalid JSON shows the first error with its line and column. The check is strict RFC 8259, so text that passes here is read by any conforming parser. Only the first error is reported; fix it and the next one, if there is one, appears.

Why is my JSON invalid when it works in JavaScript?

Because a JavaScript object literal isn’t JSON. JavaScript accepts unquoted keys, single quotes, trailing commas, comments and values like undefined; JSON accepts none of them. Keys and strings need double quotes, and the only literals are true, false and null.

Does formatting change my data?

No: formatting and minifying only add or remove whitespace between tokens, and numbers and strings are copied character for character. The one optional change is Sort keys, which reorders object members. JSON objects are unordered by definition, so that doesn’t change their meaning.

How do I pretty-print JSON in code or the terminal?

In JavaScript, JSON.stringify(value, null, 2) indents by two spaces; in a shell, jq . file.json or python3 -m json.tool file.json does the same. These parse the numbers before printing them: JavaScript loses digits past 2^53, and so does jq before version 1.7.