Skip to content

Pretty print JSON in Python

Short answer

To pretty print JSON in Python, parse it into Python objects and dump it with an indent: print(json.dumps(data, indent=4)). To format a file without writing code, run python -m json.tool data.json.

Updated · 4 min read

Pretty print JSON with json.dumps

import json

reading = {
    "station": "São Paulo-Mirante",
    "temp_c": 24.5,
    "alerts": ["heat", "uv"],
    "calibrated": True,
    "battery": None,
}
print(json.dumps(reading, indent=4))
{
    "station": "S\u00e3o Paulo-Mirante",
    "temp_c": 24.5,
    "alerts": [
        "heat",
        "uv"
    ],
    "calibrated": true,
    "battery": null
}

True and None become true and null, and non-ASCII characters are escaped (S\u00e3o) unless you pass ensure_ascii=False.

Arguments that change the output

Argument Effect
indent=2 Spaces per level. "\t" indents with tabs; 0 adds line breaks but no indent.
sort_keys=True Sorts the keys of every object, nested ones included.
ensure_ascii=False Writes ã, é and emoji as they are instead of \u escapes.
separators=(",", ":") Removes the spaces after commas and colons. With no indent, gives the smallest output.
default=str Converts values json cannot handle, such as datetime and Decimal.
print(json.dumps(reading, indent=2, sort_keys=True, ensure_ascii=False))
{
  "alerts": [
    "heat",
    "uv"
  ],
  "battery": null,
  "calibrated": true,
  "station": "São Paulo-Mirante",
  "temp_c": 24.5
}

JSON Prettier does the same in the browser, with an Escape non-ASCII switch that matches ensure_ascii.

Write it to a file

with open("reading.json", "w", encoding="utf-8") as f:
    json.dump(reading, f, indent=2, ensure_ascii=False)
    f.write("\n")

json.dump writes to a file object and adds no final newline. Pass encoding="utf-8": before Python 3.15, Windows defaults to a legacy code page, and characters outside it raise UnicodeEncodeError.

To reformat a file in place, read it in one with block and write it in a second. Opening with "w" empties the file at once, so it must come after json.load:

with open("export.json", encoding="utf-8") as f:
    data = json.load(f)

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

json.dump(data, sys.stdout, indent=2) prints in chunks, without building one large string the way print(json.dumps(...)) does.

From the terminal: json.tool

python -m json.tool reading.json
python -m json.tool --indent 2 --sort-keys reading.json
python -m json.tool raw.json pretty.json
curl -s https://api.github.com/repos/python/cpython | python -m json.tool

The third line writes to pretty.json. Python 3.14 added python -m json as the preferred spelling and colors the output in a terminal; json.tool still works. Use python3 on macOS and Linux, and py on Windows if python is not found.

Flag Effect
--indent N N spaces per level; the default is 4
--tab Indent with tabs
--sort-keys Sort object keys
--no-ensure-ascii Keep non-ASCII characters (3.9+)
--compact One line, no spaces (3.9+)
--json-lines One document per input line (3.8+)

Floats are rewritten on the way through: {"price": 19.90, "qty": 1e2} prints as 19.9 and 100.0. Integers of any size survive, and jq 1.7 and later keep 19.90 as written. Invalid input prints the parser’s message and exits with status 1:

$ echo '{"temp_c": 24.5,}' | python -m json
Illegal trailing comma before end of object: line 1 column 16 (char 15)

For jq, Node.js and PowerShell, see pretty print JSON on the command line.

pprint is not JSON

from pprint import pprint
pprint(reading)
{'alerts': ['heat', 'uv'],
 'battery': None,
 'calibrated': True,
 'station': 'São Paulo-Mirante',
 'temp_c': 24.5}

Single quotes, True and None make this invalid JSON, and keys are sorted unless you pass sort_dicts=False or call pprint.pp. Use it for debugging, and json.dumps for anything that must be JSON.

Pretty print an API response

import json
import requests

r = requests.get("https://api.github.com/repos/python/cpython", timeout=10)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))

Don’t pass r.text to json.dumps. It is already a string, so you get one quoted line full of backslashes:

raw = '{"station": "Mirante", "temp_c": 24.5}'
print(json.dumps(raw, indent=2))
"{\"station\": \"Mirante\", \"temp_c\": 24.5}"

Parse it with json.loads(raw) first. The same goes for JSON inside a string field, common in webhook and queue payloads:

event = {"type": "invoice.paid", "body": "{\"invoice\": \"INV-88\", \"amount\": 120}"}
event["body"] = json.loads(event["body"])
print(json.dumps(event, indent=2))

If .json() fails with Expecting value: line 1 column 1 (char 0), the server sent HTML or an empty body: see JSONDecodeError: Expecting value.

JSON Lines logs

.jsonl (NDJSON) files hold one document per line, so json.load fails on them. Format line by line:

with open("events.jsonl", encoding="utf-8") as f:
    for line in f:
        if line.strip():
            print(json.dumps(json.loads(line), indent=2))

The if skips blank lines. python -m json.tool --json-lines stops at the first one with Expecting value: line 2 column 1 (char 1).

Values json cannot write

TypeError: Object of type datetime is not JSON serializable
when serializing dict item 'taken_at'

datetime, Decimal, set and your own classes raise this; Python 3.14 adds the second line, which names the key. Pass default=str, or default=lambda o: o.isoformat() when the unknown values are dates.

Keys must be strings. int, float, bool and None keys are converted ({7: "x"} becomes {"7": "x"}), and anything else fails with TypeError: keys must be str, int, float, bool or None, not tuple.

float("nan") and float("inf") are written as NaN and Infinity, which are not valid JSON and make a browser’s JSON.parse throw. allow_nan=False raises ValueError: Out of range float values are not JSON compliant instead. For the browser side, see pretty print JSON in JavaScript; every other guide is in JSON guides.

Questions

Does json.dumps keep the key order?

Yes. Dicts keep insertion order, and json.load builds them in file order, so the output matches the input unless you pass sort_keys=True.

How do I print JSON with colors?

In a terminal, python -m json on Python 3.14 and later colors its output. Inside a program, the third-party rich package has print_json: from rich import print_json, then print_json(data=reading).

How do I pretty print a dataclass?

Convert it to a dict first: json.dumps(dataclasses.asdict(obj), indent=2). asdict also converts nested dataclasses, lists and dicts.

Tools for this

Esc