(Note: The code in this answer only works with json.dumps() which returns a JSON formatted string, but not with json.dump() which writes directly to file-like objects. There's a modified version of it that works with both in my answer to the question Write two-dimensional list to JSON file.)

Updated

Below is a version of my original answer that has been revised several times. Unlike the original, which I posted only to show how to get the first idea in J.F.Sebastian's answer to work, and which like his, returned a non-indented string representation of the object. The latest updated version returns the Python object JSON formatted in isolation.

The keys of each coordinate dict will appear in sorted order, as per one of the OP's comments, but only if a sort_keys=True keyword argument is specified in the initial json.dumps() call driving the process, and it no longer changes the object's type to a string along the way. In other words, the actual type of the "wrapped" object is now maintained.

I think not understanding the original intent of my post resulted in number of folks downvoting it—so, primarily for that reason, I have "fixed" and improved my answer several times. The current version is a hybrid of my original answer coupled with some of the ideas @Erik Allik used in his answer, plus useful feedback from other users shown in the comments below this answer.

The following code appears to work unchanged in both Python 2.7.16 and 3.7.4.

from _ctypes import PyObj_FromPtr
import json
import re

class NoIndent(object):
    """ Value wrapper. """
    def __init__(self, value):
        self.value = value


class MyEncoder(json.JSONEncoder):
    FORMAT_SPEC = '@@{}@@'
    regex = re.compile(FORMAT_SPEC.format(r'(\d+)'))

    def __init__(self, **kwargs):
        # Save copy of any keyword argument values needed for use here.
        self.__sort_keys = kwargs.get('sort_keys', None)
        super(MyEncoder, self).__init__(**kwargs)

    def default(self, obj):
        return (self.FORMAT_SPEC.format(id(obj)) if isinstance(obj, NoIndent)
                else super(MyEncoder, self).default(obj))

    def encode(self, obj):
        format_spec = self.FORMAT_SPEC  # Local var to expedite access.
        json_repr = super(MyEncoder, self).encode(obj)  # Default JSON.

        # Replace any marked-up object ids in the JSON repr with the
        # value returned from the json.dumps() of the corresponding
        # wrapped Python object.
        for match in self.regex.finditer(json_repr):
            # see https://stackoverflow.com/a/15012814/355230
            id = int(match.group(1))
            no_indent = PyObj_FromPtr(id)
            json_obj_repr = json.dumps(no_indent.value, sort_keys=self.__sort_keys)

            # Replace the matched id string with json formatted representation
            # of the corresponding Python object.
            json_repr = json_repr.replace(
                            '"{}"'.format(format_spec.format(id)), json_obj_repr)

        return json_repr


if __name__ == '__main__':
    from string import ascii_lowercase as letters

    data_structure = {
        'layer1': {
            'layer2': {
                'layer3_1': NoIndent([{"x":1,"y":7}, {"x":0,"y":4}, {"x":5,"y":3},
                                      {"x":6,"y":9},
                                      {k: v for v, k in enumerate(letters)}]),
                'layer3_2': 'string',
                'layer3_3': NoIndent([{"x":2,"y":8,"z":3}, {"x":1,"y":5,"z":4},
                                      {"x":6,"y":9,"z":8}]),
                'layer3_4': NoIndent(list(range(20))),
            }
        }
    }

    print(json.dumps(data_structure, cls=MyEncoder, sort_keys=True, indent=2))

Output:

{
  "layer1": {
    "layer2": {
      "layer3_1": [{"x": 1, "y": 7}, {"x": 0, "y": 4}, {"x": 5, "y": 3}, {"x": 6, "y": 9}, {"a": 0, "b": 1, "c": 2, "d": 3, "e": 4, "f": 5, "g": 6, "h": 7, "i": 8, "j": 9, "k": 10, "l": 11, "m": 12, "n": 13, "o": 14, "p": 15, "q": 16, "r": 17, "s": 18, "t": 19, "u": 20, "v": 21, "w": 22, "x": 23, "y": 24, "z": 25}],
      "layer3_2": "string",
      "layer3_3": [{"x": 2, "y": 8, "z": 3}, {"x": 1, "y": 5, "z": 4}, {"x": 6, "y": 9, "z": 8}],
      "layer3_4": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    }
  }
}
Answer from martineau on Stack Overflow
Top answer
1 of 16
32

(Note: The code in this answer only works with json.dumps() which returns a JSON formatted string, but not with json.dump() which writes directly to file-like objects. There's a modified version of it that works with both in my answer to the question Write two-dimensional list to JSON file.)

Updated

Below is a version of my original answer that has been revised several times. Unlike the original, which I posted only to show how to get the first idea in J.F.Sebastian's answer to work, and which like his, returned a non-indented string representation of the object. The latest updated version returns the Python object JSON formatted in isolation.

The keys of each coordinate dict will appear in sorted order, as per one of the OP's comments, but only if a sort_keys=True keyword argument is specified in the initial json.dumps() call driving the process, and it no longer changes the object's type to a string along the way. In other words, the actual type of the "wrapped" object is now maintained.

I think not understanding the original intent of my post resulted in number of folks downvoting it—so, primarily for that reason, I have "fixed" and improved my answer several times. The current version is a hybrid of my original answer coupled with some of the ideas @Erik Allik used in his answer, plus useful feedback from other users shown in the comments below this answer.

The following code appears to work unchanged in both Python 2.7.16 and 3.7.4.

from _ctypes import PyObj_FromPtr
import json
import re

class NoIndent(object):
    """ Value wrapper. """
    def __init__(self, value):
        self.value = value


class MyEncoder(json.JSONEncoder):
    FORMAT_SPEC = '@@{}@@'
    regex = re.compile(FORMAT_SPEC.format(r'(\d+)'))

    def __init__(self, **kwargs):
        # Save copy of any keyword argument values needed for use here.
        self.__sort_keys = kwargs.get('sort_keys', None)
        super(MyEncoder, self).__init__(**kwargs)

    def default(self, obj):
        return (self.FORMAT_SPEC.format(id(obj)) if isinstance(obj, NoIndent)
                else super(MyEncoder, self).default(obj))

    def encode(self, obj):
        format_spec = self.FORMAT_SPEC  # Local var to expedite access.
        json_repr = super(MyEncoder, self).encode(obj)  # Default JSON.

        # Replace any marked-up object ids in the JSON repr with the
        # value returned from the json.dumps() of the corresponding
        # wrapped Python object.
        for match in self.regex.finditer(json_repr):
            # see https://stackoverflow.com/a/15012814/355230
            id = int(match.group(1))
            no_indent = PyObj_FromPtr(id)
            json_obj_repr = json.dumps(no_indent.value, sort_keys=self.__sort_keys)

            # Replace the matched id string with json formatted representation
            # of the corresponding Python object.
            json_repr = json_repr.replace(
                            '"{}"'.format(format_spec.format(id)), json_obj_repr)

        return json_repr


if __name__ == '__main__':
    from string import ascii_lowercase as letters

    data_structure = {
        'layer1': {
            'layer2': {
                'layer3_1': NoIndent([{"x":1,"y":7}, {"x":0,"y":4}, {"x":5,"y":3},
                                      {"x":6,"y":9},
                                      {k: v for v, k in enumerate(letters)}]),
                'layer3_2': 'string',
                'layer3_3': NoIndent([{"x":2,"y":8,"z":3}, {"x":1,"y":5,"z":4},
                                      {"x":6,"y":9,"z":8}]),
                'layer3_4': NoIndent(list(range(20))),
            }
        }
    }

    print(json.dumps(data_structure, cls=MyEncoder, sort_keys=True, indent=2))

Output:

{
  "layer1": {
    "layer2": {
      "layer3_1": [{"x": 1, "y": 7}, {"x": 0, "y": 4}, {"x": 5, "y": 3}, {"x": 6, "y": 9}, {"a": 0, "b": 1, "c": 2, "d": 3, "e": 4, "f": 5, "g": 6, "h": 7, "i": 8, "j": 9, "k": 10, "l": 11, "m": 12, "n": 13, "o": 14, "p": 15, "q": 16, "r": 17, "s": 18, "t": 19, "u": 20, "v": 21, "w": 22, "x": 23, "y": 24, "z": 25}],
      "layer3_2": "string",
      "layer3_3": [{"x": 2, "y": 8, "z": 3}, {"x": 1, "y": 5, "z": 4}, {"x": 6, "y": 9, "z": 8}],
      "layer3_4": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    }
  }
}
2 of 16
18

A bodge, but once you have the string from dumps(), you can perform a regular expression substitution on it, if you're sure of the format of its contents. Something along the lines of:

s = json.dumps(data_structure, indent=2)
s = re.sub('\s*{\s*"(.)": (\d+),\s*"(.)": (\d+)\s*}(,?)\s*', r'{"\1":\2,"\3":\4}\5', s)
🌐
Vertabelo Academy
academy.vertabelo.com › course › python-json › writing-json-files › writing-to-json-file › jsondumps-options-the-indent
How to Read and Write JSON Files in Python | Learn Python | Vertabelo Academy
First of all, we can use the indent ... of spaces per level that should be used to indent the content. An indent level of 0 or negative will only insert newlines....
🌐
Python
docs.python.org › 3 › library › json.html
JSON encoder and decoder — Python 3.14.3 documentation
If indent is a non-negative integer or string, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0, negative, or "" will only insert newlines. None (the default) selects the most compact ...
🌐
Pradet
quentin.pradet.me › blog › indenting-json-in-python.html
Indenting JSON in Python
def output_unescaped_json(value, *, indent=0): out = '' next_indent = indent + 2 if isinstance(value, int): out += str(value) elif isinstance(value, list): # opening [ and indentation until first item out += '[\n' + ' ' * next_indent # each item separated by commas and indentation out_items = [ output_unescaped_json(item, indent=next_indent) for item in value ] sep = ',\n' + ' ' * next_indent out += sep.join(out_items) # indentation between the last item and ] out += '\n' + ' ' * indent + ']' else: assert False, type(value) return out · As with textbook recursive algorithms, it is elegant because you're only solving one problem at a time, but it can be tricky to get to the solution, convince you that it works, and debug it.
🌐
ReqBin
reqbin.com › code › python › 0l6wsqxp › python-pretty-print-json-example
How do I pretty print JSON in Python?
First, you need to use the json.loads() method to convert the JSON string into a Python object. Then you need to use json.dumps() to convert the Python object back to JSON. The json.dumps() method takes a number of parameters, including the "indent" level for the JSON arrays, which will be used to pretty-print the JSON string. If the json.dumps() indentation parameter is negative 0, or an empty string, then there is no indentation, and only newlines are inserted.
🌐
DigitalOcean
digitalocean.com › community › tutorials › python-pretty-print-json
How to Pretty Print JSON in Python | DigitalOcean
September 16, 2025 - You’ll learn how to serialize custom Python objects, process massive JSON files without running out of memory, and leverage high-performance alternative libraries to speed up your applications. ... Use indent and sort_keys in json.dumps() to instantly make your JSON output readable and consistently structured.
🌐
Real Python
realpython.com › python-json
Working With JSON Data in Python – Real Python
August 20, 2025 - Free Bonus: Click here to download the free sample code that shows you how to work with JSON data in Python. When you pass in hello_frieda.json to json.tool, then you can pretty print the content of the JSON file in your terminal. When you set --indent, then you can control which indentation level json.tool uses to display the code:
Find elsewhere
Top answer
1 of 15
3096

Use the indent= parameter of json.dump() or json.dumps() to specify how many spaces to indent by:

>>> import json
>>> your_json = '["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> parsed = json.loads(your_json)
>>> print(json.dumps(parsed, indent=4))
[
    "foo",
    {
        "bar": [
            "baz",
            null,
            1.0,
            2
        ]
    }
]

To parse a file, use json.load():

with open('filename.txt', 'r') as handle:
    parsed = json.load(handle)
2 of 15
500

You can do this on the command line:

python3 -m json.tool some.json

(as already mentioned in the commentaries to the question, thanks to @Kai Petzke for the python3 suggestion).

Actually python is not my favourite tool as far as json processing on the command line is concerned. For simple pretty printing is ok, but if you want to manipulate the json it can become overcomplicated. You'd soon need to write a separate script-file, you could end up with maps whose keys are u"some-key" (python unicode), which makes selecting fields more difficult and doesn't really go in the direction of pretty-printing.

You can also use jq:

jq . some.json

and you get colors as a bonus (and way easier extendability).

Addendum: There is some confusion in the comments about using jq to process large JSON files on the one hand, and having a very large jq program on the other. For pretty-printing a file consisting of a single large JSON entity, the practical limitation is RAM. For pretty-printing a 2GB file consisting of a single array of real-world data, the "maximum resident set size" required for pretty-printing was 5GB (whether using jq 1.5 or 1.6). Note also that jq can be used from within python after pip install jq.

🌐
PYnative
pynative.com › home › python › json › python prettyprint json data
Python PrettyPrint JSON Data
May 14, 2021 - The pprint module provides the capability to “pretty-print” any Python data structures. Now, let’s see how to use the pprint module to pretty-print JSON data. The pprint.pprint() function print the formatted representation of a JSON on the configured stream, followed by a newline · Construct a PrettyPrinter instance first by configuring indent and width values.
🌐
GitHub
gist.github.com › jannismain › e96666ca4f059c3e5bc28abb711b5c92
A JSON Encoder in Python, that puts small lists on single lines. · GitHub
$ python3 CompactJSONEncoder.py --example { "compact_object": { "first": "element", "second": 2 }, "compact_list": ["first", "second"], "long_list": [ "this", "is", "a", "rather", "long", "list" ] } ... @keithzg Ahh, I see what the problem is: json.dump works with indent parameters given as int and str, while my encoder assumes and int to multiply my indentation level with.
🌐
Python
bugs.python.org › issue29636
Issue 29636: Specifying indent in the json.tool command - Python tracker
This issue tracker has been migrated to GitHub, and is currently read-only. For more information, see the GitHub FAQs in the Python's Developer Guide · This issue has been migrated to GitHub: https://github.com/python/cpython/issues/73822
🌐
GeeksforGeeks
geeksforgeeks.org › json-dumps-in-python
json.dumps() in Python - GeeksforGeeks
If indent is a string (such as "\t"), that string is used to indent each level. separators: If specified, separators should be an (item_separator, key_separator) tuple. The default is (', ', ': ') if indent is None and (', ', ': ') otherwise.
Published   June 19, 2024
🌐
Medium
medium.com › @blogshub4 › how-to-pretty-print-a-json-string-in-python-98a85f99ecb4
How to Pretty Print a JSON String in Python | by Blogshub | Medium
December 22, 2024 - Pretty Print JSON with Indentation: Use the json.dumps() method to convert the Python object back into a JSON string, and specify the indent parameter to define the level of indentation for readability.
🌐
GitHub
gist.github.com › koddr › 1335333ef927a8ac1cd6274aea7d25c3
Python: JSON only get keys in first level · GitHub
Python: JSON only get keys in first level. GitHub Gist: instantly share code, notes, and snippets.
🌐
Reddit
reddit.com › r/learnpython › formatting json output in python
r/learnpython on Reddit: formatting json output in Python
May 12, 2022 -

Hi,

I would like to read json into Python code, and then output processed json. In order to get started with this, I have written very basic Python, and am attempting to read in very basic json I found online.

The input json is:

{
    "firstName": "John",
    "lastName": "Doe",
    "hobbies": ["biking", "coding", "rapping"],
    "age": 35,
    "children": [
        {
            "firstName": "hector",
            "age": 6
        },
        {
            "firstName": "cassandra",
            "age": 8
        }
    ]
}

The code is:

import json

if __name__ == '__main__':
    
    print( "start" )

    # read and load input json
    json_input_filename = "input.json"
    json_input = open( json_input_filename )

    json_input_dict = json.load( json_input )

    # write output json
    json_output_filename = "output.json"
    with open( json_output_filename, 'w' ) as json_output:
        json.dump( json_string, json_output )
  

    print( f"end" )

and the output is:

"{\"firstName\": \"John\", \"lastName\": \"Doe\", \"hobbies\": [\"biking\", \"coding\", \"rapping\"], \"age\": 35, \"children\": [{\"firstName\": \"hector\", \"age\": 6}, {\"firstName\": \"cassandra\", \"age\": 8}]}"

What can I do in order to preserve something resembling the original formatting? I'm going to load this output into some other code in order to process it further.

Thank you very much

🌐
GeeksforGeeks
geeksforgeeks.org › python › python-pretty-print-json
Python - Pretty Print JSON - GeeksforGeeks
July 23, 2025 - If the indent parameter of json.dumps() is negative, 0, or an empty string then there are no indentations and only newlines are inserted. By default, the indent is None and the data is represented in a single line. The code takes a JSON string containing student records, parses it into a Python data structure, then pretty-prints the JSON data with proper indentation for improved readability.