Paste JSON to format it at once, and pick one of five styles by size
The JSON formatter and minifier either spreads a squashed one-line JSON into a readable layout (formatting, pretty-printing, beautifying) or strips the whitespace and line breaks to make it short (minifying). The result updates as you type, and the five sample cards at the top show how the 2-space, 4-space, tab, fit-width and one-line styles look, along with their size, line count and size after gzip. Pick the style that suits where the JSON is going, then copy it or save it as a file.
The tool never touches the values. Numbers such as 9007199254740993 or 1.50 are copied exactly as written, and a key that appears twice is kept both times. Only the whitespace and line breaks change, plus the key order and string notation when you choose to change them. On top of that, it decodes text that PHP sent as \u00e9\u00e8 into plain characters, repairs config files that mix in comments and trailing commas, and unwraps JSON copied from a log in the {\"a\":1} form by removing the backslashes.
When you need to expand or shrink JSON
JSON was designed for programs to exchange data, so it often arrives in a shape that is hard to read. These are the situations where this tool helps.
- Checking an API response: a response copied from the browser developer tools or curl is usually one line. Expanding it with 2 spaces shows at once which value sits inside which object.
- Seeing text as
\u00e9\u00fc: PHP's json_encode and Python's json.dumps write non-ASCII characters as \u escapes by default. Switching Characters to 'Decode \u' lets you read the same values as real text. - Comparing config files or test fixtures: if only the key order differs, a diff tool reports almost every line as changed. Format both files with 'Sorted' first and only the values that really differ remain.
- Pulling JSON out of a log: logs and database cells often hold JSON wrapped in a string once more, such as
{\"event\":\"login\"}. Remove the backslashes, or extract the JSON from inside the string, and then format it. - Reducing the size to send or store: one-line minifying cuts bytes for certain, but the gap shrinks when the server sends the response with gzip. Check the gzip size on the sample cards for the real effect first.
How to use it
- Paste JSON into the input box. You can also press 'Open file' or drop a .json file on the box, up to 5 MB.
- Choose the output style on the sample cards. Click a card, or move between cards with the arrow keys while one has focus.
- If needed, change the key order (Original or Sorted), the characters (As written, Decode \u, To ASCII) and the line length for Fit width (60, 80, 100 or 120 columns). The numbers on the sample cards change with them.
- If there is a syntax error, the result box switches to an error diagnosis. It shows the line and column where it stopped and the source around it, and when the notation can be repaired a 'Fix N places and format' button appears.
- Use 'Copy result' to put it on the clipboard or 'Save as file' to download it. The one-line style is saved with a .min.json ending.
The five styles compared
The five styles hold the same values and differ only in whitespace and line breaks. The table below shows the first on-screen example, 'One-line API reply' (an order of 443 bytes), converted to each style. Size is in UTF-8 bytes, and gzip is the size measured with the browser's gzip compression.
| Style | Line breaks and indentation | Lines | Size | gzip |
|---|---|---|---|---|
| 2 spaces | One line per value, 2 spaces per level | 38 | 661 B | 368 B |
| 4 spaces | One line per value, 4 spaces per level | 38 | 815 B | 374 B |
| Tab | One line per value, 1 tab per level | 38 | 584 B | 362 B |
| Fit width | Objects and arrays that fit in 80 columns stay on one line, longer ones are expanded with 2 spaces | 23 | 573 B | 359 B |
| One line | No whitespace or line breaks | 1 | 443 B | 320 B |
Minifying to one line saves 33% of the bytes compared with 2 spaces, but the gzip size shrinks by only 13%. That is because gzip already replaces repeated runs of whitespace with short codes. So when a web server compresses its responses, deleting whitespace gains less than you might expect, and logs or configs that people will read again can stay in the formatted shape. Where no compression applies, such as an input field with a character limit, an environment variable or a single database cell, the one-line style is clearly shorter. The tab uses only one byte per level, so it is the smallest of 2 spaces, 4 spaces and tab.
How Fit width breaks lines
Fit width looks at the outermost value first and asks whether it would fit within the line length if written on one line. If it does, it is written in one line like {"x": 1, "y": 2}. If not, it is expanded and the values inside are checked the same way. The line length includes the indentation, the key name and the trailing comma. Korean, Chinese, kana and full-width characters and emoji take two columns in a monospaced font, so they count as 2 (the W and F characters of Unicode East Asian Width, UAX #11).
It helps most with data that holds many short arrays. The map format GeoJSON writes each position as a number array [longitude, latitude] (RFC 7946 §3.1.1), so expanding with 2 spaces gives every number its own line. The example 'Coordinates (GeoJSON)' takes 53 lines with 2 spaces, but with Fit width each position takes one line and the total is 25 lines.
Producing the same style in other tools
These are the options to use when a program has to produce the same shape. For data whose number notation and key order do not change and whose strings contain no escapes such as \u or \/, the correspondence below gives the same characters as this tool. JavaScript can change numbers and key order when it reads values, so see the section on numbers and duplicate keys as well.
| This tool | JavaScript | Python (json) | jq |
|---|---|---|---|
| 2 spaces | JSON.stringify(v, null, 2) | json.dumps(v, indent=2, ensure_ascii=False) | jq . |
| 4 spaces | JSON.stringify(v, null, 4) | indent=4 | jq --indent 4 . |
| Tab | JSON.stringify(v, null, "\t") | indent="\t" | jq --tab . |
| One line | JSON.stringify(v) | separators=(",", ":") | jq -c . |
| Sorted | No standard option (sort yourself) | sort_keys=True | jq -S . |
| To ASCII | No standard option | ensure_ascii=True (default) | jq -a . |
| Fit width | No standard option | No standard option | No option |
The indentation of JSON.stringify grows only up to 10 spaces, and the --indent of jq accepts up to 7. When you pass indent, Python drops the space after the comma ((",", ": ")), and without indent it uses (", ", ": "). PHP's json_encode formats with 4 spaces when you pass JSON_PRETTY_PRINT, and by default it writes non-ASCII characters as \u escapes and slashes as \/. To get plain characters, pass JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES together.
Characters: decoding or creating \u escapes
A character inside a JSON string can be written as itself, or as a backslash and u followed by four hexadecimal digits (RFC 8259 §7). The two notations are the same value, so whichever you pick, the receiving program reads the same content. The default 'As written' leaves the notation you typed alone, and only the two options below change the characters of a string.
| Input (As written) | Decode \u | To ASCII | Note |
|---|---|---|---|
"\u65e5\u672c\u8a9e" | "日本語" | "\u65e5\u672c\u8a9e" | Three Japanese characters, a shape often seen in default PHP and Python output |
"\ud83d\ude4f" | "🙏" | "\ud83d\ude4f" | A character above U+FFFF is written as a surrogate pair, that is, two escapes (12 characters) |
"https:\/\/example.com" | "https://example.com" | "https:\/\/example.com" | \/ is the same character as /. To ASCII keeps an escape that is already there |
"caf\u00e9" | "café" | "caf\u00e9" | Accents on Latin letters work the same way |
"é😀" | "é😀" | "\u00e9\ud83d\ude00" | To ASCII turns every character from number 127 (DEL) up into lowercase \u notation |
"naïve\nnote" | "naïve\nnote" | "na\u00efve\nnote" | A line break \n cannot appear raw inside a string, so it stays an escape either way |
"a\u0009b" | "a\u0009b" | "a\u0009b" | Control characters such as a tab are not decoded |
"\u200b" | "\u200b" | "\u200b" | Invisible characters such as a zero-width space are not decoded either |
'Decode \u' leaves characters that cannot be told apart on screen as escapes: control characters, zero-width spaces, line and paragraph separators, and special spaces that look like an ordinary space (U+00A0 and the like). If they were decoded, you could not tell from the result whether such a character is there. 'To ASCII' goes the other way and turns every character outside ASCII into lowercase \u notation. It matches the default output of Python's json.dumps (ensure_ascii=True) and the -a option of jq, and it is useful for older systems or transfer paths that only pass ASCII safely.
If the input contains characters written as \u escapes, 'N characters written as \u or \/ escapes' and a 'Decode to characters' button appear below the formatted result. The example 'PHP reply (\u escapes)' is shown with 'Decode \u' from the start, so compare the input box with the result box.
Sorting keys by name
A JSON object is an unordered collection of names and values (RFC 8259 §1). Changing the key order therefore leaves the values the same, and fixing one order means that when you compare two JSON documents or read a version history, only the lines that really changed stand out. 'Sorted' arranges the keys of objects at every level by these rules.
- Keys are compared by Unicode code point. The order is digits, uppercase letters, underscore, lowercase letters, accented Latin letters, then CJK characters, for example
2024,Zip,_id,age,é,名前. The-Sof jq andsort_keys=Trueof Python give the same order. - The order inside arrays is not changed, because an array is a list in which the order itself carries meaning.
- If the same key appears twice, both are kept in their original relative order.
- Keys are compared with their escapes decoded.
"\u0041"and"A"count as the same name.
For config files whose entries were ordered by hand for readability, though, keeping the original order is better. RFC 8259 also notes that JSON libraries differ in whether they expose the order of object members to the program, so if some program relies on the order, do not use the sorted result as it is.
Numbers and duplicate keys are copied as they are
Reading JSON into program values and writing it out again can change the content even when it looks the same. JavaScript's JSON.parse turns numbers into 64-bit floating point (IEEE 754 binary64), so the last digits of a long integer change, integer-like keys move to the front, and for a key that appears twice only the last value survives. This tool reads the characters directly and only lays out the whitespace again, so the characters you typed remain, as the table below shows.
| Input | This tool (one line) | Rewritten after JSON.parse | What changes |
|---|---|---|---|
{"id":9007199254740993} | {"id":9007199254740993} | {"id":9007199254740992} | Last digit of an integer above 253 |
{"price":1.50} | {"price":1.50} | {"price":1.5} | Zero after the decimal point |
{"n":1E3} | {"n":1E3} | {"n":1000} | Exponent notation |
{"x":-0} | {"x":-0} | {"x":0} | Sign of negative zero |
{"b":1,"2024":2} | {"b":1,"2024":2} | {"2024":2,"b":1} | Integer-like key moves to the front |
{"a":1,"a":2} | {"a":1,"a":2} | {"a":2} | The earlier value of a duplicate key disappears |
Whether the program that receives the result runs into the same problem is a separate matter. RFC 8259 says that numbers within the precision and range of binary64 are the ones that different parties read as the same value (§6), and that for an object with repeated names, receiving software behaves differently: some use only the last value, some report an error, some report all of them (§4). Send long identifiers as strings, and merge duplicate keys into one before sending. The warning chips below the formatted result point out such values, and clicking a chip selects that spot in the input box.
When it will not format: common errors and automatic fixes
When the result box switches to an error diagnosis, it shows the line and column where checking stopped and the piece of source around it. The real mistake is often right before the marked spot. The notations below can be turned into JSON syntax in one step with 'Fix and format' or 'Remove backslashes and format', and the line layout stays as it is, with only the marked spots changed.
| Input | What is wrong | Fixed result |
|---|---|---|
{"a": 1,} | Comma after the last item | {"a": 1} |
{"a": 1 /* note */} | Comment (exists only in JSONC and JSON5) | {"a": 1 } |
{'name': 'Emma'} | Single-quoted string | {"name": "Emma"} |
{name: "Emma"} | Key without quotes | {"name": "Emma"} |
{"ok": True, "memo": None} | Python notation | {"ok": true, "memo": null} |
[1, NaN, 3] | A numeric value JSON does not have | [1, null, 3] |
{\"a\":1} | A backslash before every quote | {"a":1} |
Some cases are not fixed automatically. If a response was cut off and the brackets are not closed, there is no way to know where the original data ended, so the diagnosis only tells you which closing characters would have to be added at the end. A number with leading zeros such as 007 is left alone, because a person has to decide whether it is a number or text. In such cases, use 'Show in input' to select the spot and fix it by hand, or use the JSON validator, which shows the position and cause of the error in more detail. Some fixes change the value, such as turning NaN into null, so check the result once.
Common mistakes
- Overwriting the original config file with the fixed result: the automatic fix deletes comments. Keep the original of a JSONC file separately, and use the formatted result only where plain JSON is required.
- Sorting only one of two files before comparing: the order difference makes almost every line look changed. Format both files with the same options.
- Sending the 'Decode \u' result to a place that accepts only ASCII: the decoded text goes out as UTF-8 bytes. If the receiver cannot handle UTF-8, choose 'To ASCII'.
- Reading the formatted result with JSON.parse and trusting the numbers: this tool keeps 9007199254740993, but reading it again in JavaScript gives 9007199254740992.
- Trying to cut the transfer size with one-line minifying alone: with gzip responses the difference is small. Removing fields you do not use saves more.
- Pasting JSONL (one JSON per line) as a single document: you get an error that more characters follow after the first value. Convert it to an array with a JSON array to JSONL converter and then format it.
Limits and cautions
- The output is always standard JSON (RFC 8259). Comments and trailing commas from JSONC or JSON5 can be removed by the automatic fix and then formatted, but the tool never formats while keeping the comments.
- It handles up to 5 MB and 500 levels of nesting. If the result exceeds 300,000 characters, syntax coloring is skipped for speed and only plain text is shown.
- The character widths used by Fit width are approximate values counted for a monospaced font. Combining characters and some symbols can have a different real width depending on the font.
- It checks syntax only. Data rules such as required keys, value types and ranges (JSON Schema) are not checked.
- The gzip size is measured with this browser's default gzip compression, so it differs if the server's compression step or another method (such as br) is used.
- The input is not saved. Refreshing the page brings back the first example.
As of RFC 8259, RFC 7946 and RFC 9110, the PHP, Python, jq and MDN documentation, and UAX #11 (Unicode 18.0.0) were checked against the originals on 2026-10-22. The size table and the output of PHP, jq and Python were produced and compared the same day with Chromium, PHP 8.5.12, jq 1.7.1 and Python 3.14.
Sources
- 01IETF RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format§1 objects are unordered, §2 four whitespace characters, §4 names should be unique and duplicates are handled differently by implementations, §6 binary64, §7 escapes and surrogate pairs, §8.1 UTF-8 and BOM
- 02PHP manual: JSON constantsJSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE (by default escaped as \uXXXX)
- 03Python documentation: json moduleensure_ascii defaults to True, indent, default separators, sort_keys
- 04MDN: JSON.stringify()The space argument goes up to 10
- 05jq manual--indent n (up to 7), --tab, --sort-keys (-S), --compact-output (-c), --ascii-output (-a), keys sorted by Unicode code point
- 06Unicode UAX #11: East Asian WidthUnicode 18.0.0, wide (W) and fullwidth (F) characters
- 07IETF RFC 7946: The GeoJSON Format§3.1.1 a position is a number array in the order longitude, latitude
- 08IETF RFC 9110: HTTP Semantics§8.4 Content-Encoding, §8.4.1.3 gzip
- 09MDN: CompressionStreamA standard API for gzip compression inside the browser, supported by the major browsers since May 2023
Frequently asked questions
What is the difference between formatting and minifying JSON?
Formatting (pretty-printing, beautifying) puts each value on its own line and adds indentation so people can read it, while minifying removes all whitespace and line breaks outside strings to make one short line. Both results hold the same values, and whitespace inside a string is data, so it stays in either case.
How is 'Fit width' different from 2-space formatting?
2-space formatting spreads out every value on its own line, so even a short array like [1, 2, 3] takes five lines. Fit width keeps an object or array on one line when it fits the chosen line length (80 columns by default) and expands it only when it does not. For data with many short arrays, such as a coordinate list, the line count drops to about half or less.
My text shows up as \u sequences. Can I change that?
Yes. Set Characters to 'Decode \u' and the \u escapes and \/ are written out as characters. PHP json_encode and Python json.dumps write non-ASCII text this way by default. The two notations are the same value, so decoding does not change the data. Characters you cannot see, such as control characters or zero-width spaces, stay escaped so you can tell them apart.
Does sorting keys by name change the data?
A JSON object is an unordered collection of names and values, so the values do not change. Sorting arranges the keys of objects at every level by Unicode code point (digits, uppercase, lowercase, then accented letters and CJK characters), and keeps the order inside arrays and the relative order of keys with the same name. If you format two JSON documents with the same options, only the values that truly differ stand out.
Are big numbers and trailing zeros kept as they are?
Yes. The tool does not calculate with numbers but copies the characters you typed, so 9007199254740993, 1.50 and 1E3 all stay as they are. If you read the result again with JavaScript JSON.parse, though, it can become something like 9007199254740992, so it is safer to exchange long identifiers as strings.
Can it format JSON with comments or trailing commas?
Plain JSON has no comments or trailing commas, so it is an error as it stands. When the error diagnosis in the result box offers a repairable notation, press 'Fix N places and format' to remove comments and turn trailing commas, single quotes, unquoted keys, True, None and NaN into JSON syntax before formatting. You can undo it with Ctrl+Z (⌘Z) in the input box.
How do I format JSON like {\"a\":1} copied from a log?
JSON with a backslash before every quote is the trace of having been wrapped once more in a string. When you paste it, the error diagnosis offers 'Remove backslashes and format', and if the outermost value is a string in double quotes it offers 'Extract and format'. Either way, one click takes out the inner JSON and formats it.
Is the JSON I enter sent to a server?
No. Formatting, minifying, error checking and measuring the gzip size all run inside this browser, and what you enter is neither sent to a server nor saved. When you refresh the page, the input is gone and the first example comes back.