How to Pretty-Print JSON in JavaScript, Python, jq and VS Code

By , founder of Softaware Commerce · Published · Updated

Drafted with AI assistance. Every command and code example was run and its output checked before publication. How guides are made

To pretty-print JSON, parse it and serialise it again with indentation: in JavaScript use JSON.stringify(value, null, 2), in Python run python3 -m json.tool file.json or call json.dumps(data, indent=2), on the command line run jq . file.json, and in VS Code run Format Document (Shift+Alt+F on Windows). All of these validate the JSON as a side effect, so a document that will not format is a document that will not parse. For a one-off paste, the JSON Formatter does the same in your browser.

Which method should I use?

Every method below produces the same data with different whitespace, so pick the one that is already where your JSON is. The table summarises the commands; each is explained in its own section.

WherePretty-printSort keysMinify
JavaScript / Node.jsJSON.stringify(v, null, 2)Sort with a replacer (see below)JSON.stringify(v)
Python (code)json.dumps(d, indent=2)sort_keys=Trueseparators=(",", ":")
Python (shell)python3 -m json.tool f.json--sort-keys--compact
jqjq . f.jsonjq -S . f.jsonjq -c . f.json
VS CodeFormat DocumentNot built inNot built in
BrowserJSON Formatter: BeautifySort keys (A-Z)Minify

How do I pretty-print JSON in JavaScript?

JSON.stringify takes three arguments: the value, a replacer and a space argument. Passing null as the replacer and a number as the space gives indented output:

const data = { name: "Ada", langs: ["en", "fr"], active: true };
console.log(JSON.stringify(data, null, 2));
{
  "name": "Ada",
  "langs": [
    "en",
    "fr"
  ],
  "active": true
}

If you start from a JSON string rather than an object, parse it first: JSON.stringify(JSON.parse(text), null, 2). The parse step throws a SyntaxError on invalid input, which makes this a validator too.

The space argument

The behaviour is defined in the ECMAScript specification and summarised on MDN:

  • A number indents each level by that many spaces. Values above 10 are treated as 10, so JSON.stringify(data, null, 20) gives the same output as 10.
  • A string is used as the indent itself, cut to its first 10 characters. Pass "\t" for tabs.
  • Omitting it, or passing 0 or an empty string, gives compact output on one line.

The replacer argument

The replacer filters or transforms values while serialising. An array of strings keeps only those property names:

JSON.stringify(data, ["name", "active"], 2);
// {
//   "name": "Ada",
//   "active": true
// }

A function is called for every key and value; returning undefined drops the property. This is a simple way to keep secrets out of logs:

const user = { user: "ada", password: "secret", token: "x" };
JSON.stringify(user, (key, value) =>
  key === "password" || key === "token" ? undefined : value, 2);
// {
//   "user": "ada"
// }

There is no built-in option to sort keys. A replacer that rebuilds each plain object with sorted entries does it:

const sortKeys = (key, value) =>
  value && typeof value === "object" && !Array.isArray(value)
    ? Object.fromEntries(Object.entries(value).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)))
    : value;

JSON.stringify({ b: 1, a: { d: 1, c: 2 } }, sortKeys, 2);

One caveat: JavaScript always lists integer-like keys such as "10" first, in numeric order, whatever order you insert them in.

What JSON.stringify changes or rejects

Pretty-printing an object built in code is not always a faithful copy of it. Date objects become ISO strings, Map and Set become {}, NaN and Infinity become null, and properties holding undefined or a function disappear. A BigInt throws TypeError: Do not know how to serialize a BigInt, and an object that refers to itself throws TypeError: Converting circular structure to JSON. Convert BigInts in a replacer, for example (k, v) => typeof v === "bigint" ? v.toString() : v.

Node.js one-liners

Node can pretty-print a file or a pipe without installing anything. Reading file descriptor 0 handles standard input:

# A file
node -e 'console.log(JSON.stringify(JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")), null, 2))' data.json

# Standard input
cat data.json | node -e 'console.log(JSON.stringify(JSON.parse(require("fs").readFileSync(0, "utf8")), null, 2))'

Note that readFileSync keeps a UTF-8 byte order mark, and JSON.parse rejects a string that starts with one. If a file saved by a Windows editor fails here but works elsewhere, a BOM is the likely cause.

How do I pretty-print JSON in Python?

From the command line: json.tool

Python's standard library includes a small command-line formatter, documented under json.tool. It reads a file or standard input, validates it and prints it with four-space indentation:

python3 -m json.tool data.json
echo '{"a":1}' | python3 -m json.tool
python3 -m json.tool data.json pretty.json   # write to a second file

The options are:

  • --indent 2 sets the number of spaces; --tab indents with tabs; --compact removes all whitespace; --no-indent puts everything on one line with spaces after separators. These four were added in Python 3.9.
  • --sort-keys sorts object keys alphabetically (Python 3.5 and later; since 3.5 the default is to keep input order).
  • --no-ensure-ascii writes characters such as ü as they are instead of ü (Python 3.9 and later).
  • --json-lines treats each input line as a separate document (Python 3.8 and later).

Python 3.14 adds the shorter python3 -m json, which behaves the same, and colours the output when it is written to a terminal. The examples here were run on Python 3.14.

$ python3 -m json.tool --indent 2 --sort-keys data.json
{
  "active": true,
  "langs": [
    "en",
    "fr"
  ],
  "name": "Ada"
}

In code: json.dumps and json.dump

json.dumps returns a string; json.dump writes to an open file. Both take the same formatting arguments:

import json

data = {"name": "Ada", "city": "Zürich", "langs": ["en", "fr"]}
print(json.dumps(data, indent=2, ensure_ascii=False))

with open("out.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)

Useful arguments are indent (a number of spaces, or a string such as "\t"), sort_keys=True, ensure_ascii=False to keep non-ASCII text readable, and default=str to turn objects the module cannot handle, such as datetime.date, into strings instead of raising TypeError: Object of type date is not JSON serializable. When you pass indent, Python already drops the space before line breaks; when you do not, it writes ", " and ": " between items.

How do I pretty-print JSON with jq?

jq is a command-line JSON processor. Its simplest filter, ., outputs the input unchanged, and jq pretty-prints with two-space indentation by default:

jq . data.json            # pretty-print a file
jq -S . data.json         # sort keys at every level
jq --indent 4 . data.json # up to 7 spaces
jq --tab . data.json      # tabs
jq -c . data.json         # compact, one line

The filter does more than format. jq '.user.name' data.json prints one field, and jq -c '.[]' list.json prints each array element on its own line, which is a quick way to turn an array into JSON Lines. Add -r to print strings without quotes.

Do not redirect jq's output to the file it is reading. jq . data.json > data.json leaves an empty file, because the shell truncates the file before jq opens it. Write to a temporary file and move it:

jq . data.json > data.tmp && mv data.tmp data.json

These examples were checked with jq 1.8.1. The jq manual explains that a number literal you do not modify is printed exactly as written, so jq . keeps a 20-digit ID intact; arithmetic on it converts it to a double and loses precision.

How do I pretty-print a curl response?

Pipe the body into jq. Use -s so curl's progress meter does not mix with the output:

curl -s https://api.github.com/repos/jqlang/jq | jq '{name, full_name, private}'
{
  "name": "jq",
  "full_name": "jqlang/jq",
  "private": false
}

Do not add -i: response headers in front of the body are not JSON, and jq stops with a parse error. If jq fails on a response that should be JSON, print it raw first; an HTML error page or an empty body is a more common cause than malformed JSON. The same pipe works with Python: curl -s URL | python3 -m json.tool.

How do I format JSON in VS Code?

Open the file and run Format Document from the Command Palette or the editor's context menu. The VS Code documentation lists the shortcut as Shift+Alt+F on Windows, Shift+Option+F on macOS and Ctrl+Shift+I on Linux. Format Selection (Ctrl+K Ctrl+F) formats only the selected text.

  • For pasted text in an unsaved tab, set the language mode to JSON first (click the language name in the status bar); a plain-text tab has no JSON formatter.
  • The indent size comes from the editor's tab settings for that file, shown in the status bar.
  • To format on every save, enable the editor.formatOnSave setting, optionally only for [json].
  • Files such as settings.json open in the "JSON with Comments" (jsonc) mode, which allows comments. That is a VS Code dialect, not JSON; a strict parser will reject those files.

How do I view formatted JSON in the browser?

Firefox has a built-in JSON viewer: open a URL served as application/json and it shows a collapsible tree with a search filter, and lets you switch to the raw text and pretty-print it. In Chrome and other Chromium browsers, open DevTools, go to the Network panel, select the request and read the body in the Response or Preview tab.

For an object you already have in the Console, the copy() helper puts it on the clipboard. Chrome documents it in its Console Utilities API and Firefox in its Web Console helpers. Stringify it first to control the indentation:

copy(JSON.stringify(data, null, 2))

If you do not want to open a terminal at all, paste the text into the JSON Formatter and click Beautify. It parses with your browser's JSON.parse and re-serialises with JSON.stringify, offers 2-space, 4-space or tab indentation and a Sort keys (A-Z) option, and runs entirely in the page. To share data as YAML instead, use JSON to YAML.

How do I minify JSON again?

Minifying is the same round trip without indentation, and it is what you normally send over an API. Each method has a compact mode:

JSON.stringify(data)                       // JavaScript
json.dumps(data, separators=(",", ":"))     # Python
python3 -m json.tool --compact data.json   # Python, shell
jq -c . data.json                          # jq

All four print {"name":"Ada","langs":["en","fr"],"active":true} for the example above. Without separators, Python's default output keeps a space after each comma and colon. The JSON Formatter's Minify button does the same in the browser. For why minified data is worth sending and where the savings really come from, see minification explained.

What if the JSON is invalid?

Every formatter here parses before it prints, so invalid input produces an error instead of formatted output. For the input {"a":1,} with its trailing comma:

ToolError message
Node.js 20SyntaxError: Expected double-quoted property name in JSON at position 7
Python 3.14Illegal trailing comma before end of object: line 1 column 7 (char 6)
jq 1.8.1jq: parse error: Expected another key-value pair at line 1, column 8

Messages differ between tools and versions, but each points to where the parser gave up, which is usually just after the real mistake. Parsers also disagree at the edges: jq accepts a file that starts with a UTF-8 byte order mark, while Python reports Unexpected UTF-8 BOM and JSON.parse rejects it. The guide to common JSON syntax errors lists each error with its fix. Comments, single quotes and trailing commas cannot be "formatted away": remove them, then format.

Quick reference

  • JavaScript: JSON.stringify(JSON.parse(text), null, 2); use "\t" for tabs; the indent is capped at 10.
  • Python shell: python3 -m json.tool --indent 2 --sort-keys --no-ensure-ascii file.json.
  • Python code: json.dumps(data, indent=2, ensure_ascii=False).
  • jq: jq . file.json, -S to sort, -c to minify; never redirect to the input file.
  • curl: curl -s URL | jq ., without -i.
  • VS Code: Format Document, Shift+Alt+F (Windows), Shift+Option+F (macOS), Ctrl+Shift+I (Linux).
  • Browser: paste into the JSON Formatter and click Beautify.

Frequently asked questions

Should I indent JSON with 2 spaces, 4 spaces or tabs?

It makes no difference to any parser, because whitespace between tokens is ignored. Two spaces is the default in jq and the usual choice in JavaScript projects; Python's json.tool defaults to four. Pick one per repository and let a formatter enforce it so diffs only show real changes.

Does pretty-printing change my data?

Usually not, but it is a parse and re-serialise, not a text edit. Duplicate keys collapse to the last value, number spellings such as 1.0 or 1e2 may be rewritten as 1 or 100 in JavaScript, and integers beyond 253 can lose precision in JavaScript. Key order is kept unless you ask for sorting.

How do I pretty-print a JSON Lines (NDJSON) file?

Each line is a separate document, so format them one by one. jq . file.jsonl handles this directly because jq reads a stream of values, and python3 -m json.tool --json-lines < file.jsonl does the same in Python. Feed the file on standard input: on Python 3.14.4, passing the file name together with --json-lines failed with I/O operation on closed file.

Why is my non-ASCII text shown as \u escapes?

Python escapes every non-ASCII character by default. Pass ensure_ascii=False to json.dumps, or --no-ensure-ascii to json.tool. Both forms are valid JSON and parse to the same string; jq does the same only if you pass -a.

Is it safe to paste confidential JSON into an online formatter?

Only if the formatter does not upload it. The CodeBeautify.dev JSON Formatter parses and formats in your browser without sending your input to a server, but for secrets such as tokens the command-line tools above keep the data on your machine entirely.

Tools for this guide