How do I pretty print JSON in Python?

Dark navy cover card with the title 'How do I pretty print JSON in Python?' in white and a green accent bar

To pretty print JSON in Python, parse it into a Python object and call json.dumps(data, indent=4). Use json.dump(data, f, indent=4) to write the formatted result to a file, or run python -m json.tool data.json to format a file from the terminal without writing any code.

Pretty print JSON in Python with json.dumps and indent

The indent argument of json.dumps is what turns one long line into readable, nested output. According to the Python json documentation, a positive integer "indents that many spaces per level", while None, the default, inserts no newlines at all.

import json

data = {"name": "Ada", "roles": ["admin", "editor"], "active": True}
print(json.dumps(data, indent=4))

The output looks like this:

{
    "name": "Ada",
    "roles": [
        "admin",
        "editor"
    ],
    "active": true
}

Python's True became JSON's true. That conversion is why you use the json module instead of printing the dictionary.

Some indent values surprise people:

  • A string such as "\t" is used as the indent for each level, so indent="\t" gives tab-indented JSON.
  • Zero, a negative number or "" inserts newlines but no indentation.
  • None (the default) keeps everything on one line.

Pretty print a JSON string

A JSON string has to be parsed before it can be re-indented, because json.dumps on a string just escapes it again. The usual pattern is json.loads followed by json.dumps, as the freeCodeCamp guide shows.

import json

raw = '{"id": 7, "tags": ["a", "b"]}'
print(json.dumps(json.loads(raw), indent=4))

If json.loads raises json.JSONDecodeError, the input isn't valid JSON yet. Fix that first; our guide to why JSON requires double quotes covers the most common cause.

Write pretty JSON to a file with json.dump

json.dump writes formatted JSON straight to a file object and takes the same arguments as json.dumps. Open the file with an explicit encoding so non-English text survives on every system.

import json

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

To reformat an existing file, read it with json.load, then write it back to a new path. Writing to a second file means a crash halfway through can't leave you with a half-written original.

Sort keys and control separators

sort_keys=True makes json.dumps output dictionaries sorted by key, which helps with diffs and snapshot tests. The docs note that keys are sorted before they're converted to strings, so numeric keys sort by value rather than as text.

print(json.dumps(data, indent=4, sort_keys=True))

Without sort_keys, the module keeps the order the data came in. The documentation says its encoders and decoders "preserve input and output order by default".

The separators argument decides the punctuation between items. When indent is set, the default is (',', ': '), so lines don't end in a stray space (that changed in Python 3.4). For the opposite of pretty printing, pass separators=(',', ':') with no indent to get the most compact JSON.

Keep accented characters and emoji readable

By default json.dumps escapes every non-ASCII character, so a name like "José" comes out as "Jos\u00e9". That output is valid JSON, but it's hard to read in a log or a config file.

Pass ensure_ascii=False to keep the characters as they are. The docs say Python then escapes only the quotation mark, the backslash and control characters U+0000 through U+001F.

print(json.dumps({"name": "José"}, indent=4, ensure_ascii=False))

Fix "Object of type datetime is not JSON serializable"

The json module only knows dictionaries, lists, strings, numbers, booleans and None. Pass it a datetime, a set or your own class and it raises a TypeError, for example TypeError: Object of type datetime is not JSON serializable, as bobbyhadz explains.

The quick fix is default=str, which runs str() on anything the encoder can't handle. It works, but a datetime then comes out space-separated rather than in ISO 8601 form. Codemia also warns that it silently converts every unsupported type, which can hide bugs.

A small default function is safer:

import json
from datetime import date, datetime

def to_json(value):
    if isinstance(value, (date, datetime)):
        return value.isoformat()
    raise TypeError(f"Cannot serialize {type(value).__name__}")

event = {"title": "Deploy", "at": datetime.now()}
print(json.dumps(event, indent=4, default=to_json))

This follows the documented contract: default should "return a JSON encodable version of the object or raise a TypeError". My take: use default=str only in a throwaway debug print, never in code that writes files or API responses.

Pretty print JSON from the command line

Python ships a JSON command-line tool, so you can format a file without writing a script. The json command-line interface validates the input and pretty-prints it.

python -m json.tool data.json
curl -s https://api.example.com/users | python -m json.tool
python -m json.tool --sort-keys data.json pretty.json

On Python 3.14 and later you can shorten that to python -m json data.json; the old json.tool form still works. Since Python 3.5 the output keeps the input's key order, and --sort-keys sorts it.

Other options:

Option What it does Added in
--sort-keys Sorts dictionary keys alphabetically 3.5
--json-lines Treats each input line as a separate JSON object 3.8
--no-ensure-ascii Keeps non-ASCII characters unescaped 3.9
--indent, --tab, --no-indent, --compact Mutually exclusive whitespace controls 3.9

If you live in the terminal, jq adds colors and filtering on top of this. The Python tool's advantage is that it's already installed wherever Python is.

json.dumps vs pprint: which one to use

pprint formats Python objects, not JSON, so its output uses single quotes, True and None. Techie Delight points out that this means the result isn't valid JSON, even though it looks similar.

Goal Use
Valid JSON to print, log or save json.dumps(data, indent=4)
Write formatted JSON to a file json.dump(data, f, indent=4)
Format a file or API response in the terminal python -m json.tool (or python -m json on 3.14+)
Quick look at a Python object while debugging pprint.pprint(data)

Use json.dumps almost every time. Output you can paste into another tool beats output that only looks right.

Limits of the standard library

The json module has one real limitation for pretty printing: it formats every nested level the same way. It can't keep a short list of tags on one line while expanding objects, and it has no color output in the documented options. For that you need a third-party formatter or a viewer.

Large integers are another catch, though that one bites when the JSON reaches JavaScript, not in Python. Our post on JSON large number precision explains why.

To read a payload once, pasting it into the JSON formatter is faster than opening a REPL. It formats in your browser, and the tool code doesn't send your input anywhere. For a refresher on the format itself, see what JSON is.

FAQ

What is the difference between json.dump and json.dumps?

json.dumps returns the JSON as a string. json.dump writes it straight to an open file object. Both take the same indent, sort_keys and ensure_ascii arguments.

How do I pretty print JSON with tabs instead of spaces in Python?

Pass a string as the indent: json.dumps(data, indent="\t"). Python has accepted strings for indent since version 3.2.

Does json.dumps keep the original key order?

Yes. Python's json module preserves input order by default. Pass sort_keys=True when you want keys in alphabetical order.

Why does pprint not give me valid JSON?

pprint prints the Python representation of the data, with single quotes, True and None. Use json.dumps with indent when the output has to be real JSON.

How do I pretty print a JSON file from the command line with Python?

Run python -m json.tool data.json. On Python 3.14 and later, python -m json data.json does the same thing.

Sources