Skip to content
LocalOnly
JSON Tools

Pretty Print JSON in the Terminal, Python and Node.js

Four ways to make JSON readable without leaving your terminal or browser, and the three edge cases where pretty printing changes the data.

Updated October 18, 20264 min readTool runs in your browser

There are several ways to pretty print JSON without leaving the terminal or the browser. The JSON Beautifier is the quickest option when the JSON is already on your clipboard. Often it is somewhere else: the output of a curl call, a line in a log file, or a response in the browser's network panel. Then the fastest path is a tool that is already in front of you.

This guide covers jq, Python, Node and browser DevTools, then the three cases where pretty printing quietly changes the data. Every output below comes from running the command on the same one-line sample file.

The sample file

order.json
{"orderId":12345678901234567890,"city":"Málaga","total":1.50,"tags":["a"],"status":"new","status":"paid"}

It is small on purpose, but it carries three traps: an integer too large for a 64-bit float, a non-ASCII character, and a key that appears twice. Watch what each tool does with them.

Pretty print JSON with jq

jq is a command-line JSON processor. The filter . means the whole document, so jq . simply prints it with two-space indentation, in colour when the output is a terminal. Install it with brew install jq on macOS or apt install jq on Debian and Ubuntu.

$ jq . order.json
{
  "orderId": 12345678901234567890,
  "city": "Málaga",
  "total": 1.50,
  "tags": [
    "a"
  ],
  "status": "paid"
}
  • jq --indent 4 . uses four spaces, and jq --tab . uses tabs.
  • jq -S . sorts keys alphabetically, which helps before a diff.
  • jq -c . does the opposite and prints one compact line.
  • jq '.status' order.json prints a single field instead of the whole document.

Pretty print JSON in Python

Any machine with Python 3 has a JSON pretty printer built in. It defaults to four-space indentation:

$ python3 -m json.tool order.json
{
    "orderId": 12345678901234567890,
    "city": "M\u00e1laga",
    "total": 1.5,
    "tags": [
        "a"
    ],
    "status": "paid"
}

Note the \u00e1 where the file had á, and 1.5 where it had 1.50. Useful options are --indent 2, --sort-keys, --compact, --json-lines for files with one JSON object per line, and --no-ensure-ascii, which keeps non-ASCII characters as they are.

Pretty print JSON in Node.js

In a JavaScript project, Node is always there. readFileSync(0) reads standard input, so the one-liner works with a file redirect or a pipe:

$ node -p 'JSON.stringify(JSON.parse(require("fs").readFileSync(0, "utf8")), null, 2)' < order.json
{
  "orderId": 12345678901234567000,
  "city": "Málaga",
  "total": 1.5,
  "tags": [
    "a"
  ],
  "status": "paid"
}

Look at orderId. The last digits changed, and nothing warned about it. The section on traps below explains why.

Pretty print JSON in the browser

In Chrome and Edge, open DevTools, select a request in the Network panel and switch to the Preview tab: JSON responses appear as a collapsible tree. Firefox goes further and opens JSON responses in a built-in viewer with Raw Data and Pretty Print views.

In the console, JSON.stringify(value, null, 2) prints an indented string, and copy(value) copies a value to the clipboard. copy is a console helper in Chrome, Edge and Firefox, not part of JavaScript, so it does not work in your own scripts.

Pretty print curl JSON output

Most of the time the JSON comes from an API call. Pipe it straight into jq or json.tool:

curl -s https://api.example.com/orders/42 | jq .
curl -s https://api.example.com/orders/42 | python3 -m json.tool

The -s flag matters. When its output goes to a pipe, curl prints a progress meter to the terminal, which gets mixed in with the formatted result you are trying to read.

Three ways pretty printing can change your data

Large integers and number formatting

JavaScript stores every number as a 64-bit float, which is exact only up to 9007199254740991. Node rounded 12345678901234567890 to 12345678901234567000. Python keeps integers exact. jq 1.7 and later keep a number exactly as written when the filter does not touch it; older releases such as 1.6 convert it to a float, like Node. Python and Node also rewrite 1.50 as 1.5, which is the same number but a different string.

Non-ASCII text

Python's json.tool escapes every non-ASCII character by default, so Málaga becomes M\u00e1laga. Both forms parse to the same string, but the file looks different and diffs badly against the original. Add --no-ensure-ascii to keep the characters.

Duplicate keys

The sample has status twice. jq, Python and Node all printed only the last value, paid, without a warning. The JSON standard says keys should be unique but leaves duplicates to each parser, and keeping the last one is the common choice. If a document might contain duplicates, check it before pretty printing, because the formatted copy hides the problem.

Frequently asked questions

Command Palette

Search for a tool or command