json.dumps

Python objects in, JSON text out. Tuples turn into arrays, every key turns into a string, and anything json does not know — sets, dates, Decimals — needs default=.

json functionPython 2.6+Live demo
Common call
json.dumps(data, indent=2, ensure_ascii=False)
Returns
str — the JSON document
Replaces
str(dict) / repr(), which produce Python syntax, not JSON
Watch out
sets, dates and Decimal raise TypeError without default=
json.dumps(objobj — dict, list, tuple, str, int, float, bool or None — nested freely. Anything else goes through default.type: any · required, *, skipkeysskipkeys — Silently drop dict keys that are not str, int, float, bool or None instead of raising TypeError.type: bool · default: False=False, ensure_asciiensure_ascii — Escape every non-ASCII character as \uXXXX (a surrogate pair above U+FFFF). False writes the characters as they are.type: bool · default: True=True, check_circularcheck_circular — Detect a container that contains itself (ValueError). False skips the check — a cycle then ends in RecursionError.type: bool · default: True=True, allow_nanallow_nan — Write NaN, Infinity and -Infinity (not valid JSON). False raises ValueError instead.type: bool · default: True=True, clscls — Encoder class to use; the other keyword arguments are passed to it.type: JSONEncoder subclass · default: None=None, indentindent — None = one line. An int puts every item on its own line, indented by that many spaces per level (0 = new lines, no spaces); a str is used as the indent itself.type: int | str | None · default: None=None, separatorsseparators — (item_separator, key_separator). Default (', ', ': '), or (',', ': ') when indent is set; (',', ':') gives the most compact output.type: tuple[str, str] · default: None=None, defaultdefault — Called with every object json cannot serialize; must return something it can (or raise TypeError).type: callable · default: None=None, sort_keyssort_keys — Write dict keys in sorted order instead of insertion order. Keys of mixed types (1 and "a") raise TypeError.type: bool · default: False=False, **kw)
→ str

Demo

Live evaluation
A dict built from your inputs, serialized with the defaults. Watch the escapes for non-ASCII text and how floats are written.
Try:
Inputs
namestrany text
tagslist[str]comma-separated
scorefloata number
Code
import json
record = {'name': 'Ada', 'tags': ['admin', 'dev'], 'score': 9.5}
json.dumps(record)
Result
'{"name": "Ada", "tags": ["admin", "dev"], "score": 9.5}'

In "accented", ë is written as \u00eb; the emoji is above U+FFFF, so ensure_ascii writes it as a surrogate pair of two \u escapes. Floats are written with repr(), so 10 typed as a float comes out as 10.0 and 1e16 as 1e+16. With indent set, the item separator drops its trailing space, and indent=0 still breaks lines. In non-str keys, the key comes back from loads as the string '1', not the int 1.

Parameters

NameTypeRequiredDescription
objanyyesdict, list, tuple, str, int, float, bool or None — nested freely. Anything else goes through default.
indentint | str | Noneno (None)None = one line. An int puts every item on its own line, indented by that many spaces per level (0 = new lines, no spaces); a str is used as the indent itself.
sort_keysboolno (False)Write dict keys in sorted order instead of insertion order. Keys of mixed types (1 and "a") raise TypeError.
ensure_asciiboolno (True)Escape every non-ASCII character as \uXXXX (a surrogate pair above U+FFFF). False writes the characters as they are.
separatorstuple[str, str]no (None)(item_separator, key_separator). Default (', ', ': '), or (',', ': ') when indent is set; (',', ':') gives the most compact output.
defaultcallableno (None)Called with every object json cannot serialize; must return something it can (or raise TypeError).
allow_nanboolno (True)Write NaN, Infinity and -Infinity (not valid JSON). False raises ValueError instead.
skipkeysboolno (False)Silently drop dict keys that are not str, int, float, bool or None instead of raising TypeError.
check_circularboolno (True)Detect a container that contains itself (ValueError). False skips the check — a cycle then ends in RecursionError.
clsJSONEncoder subclassno (None)Encoder class to use; the other keyword arguments are passed to it.

Return value

str — The JSON text. Never bytes — call .encode() yourself if you need them.

Common patterns

Pretty-print for humans
Stable key order, readable non-ASCII text.
import json
print(json.dumps(data, indent=2, sort_keys=True, ensure_ascii=False))
Compact for the wire
No spaces after , and : — the smallest output.
import json
body = json.dumps(payload, separators=(',', ':'))
Dates, Decimals and UUIDs
default= is called only for objects json cannot handle; raise TypeError for the rest.
import json
from datetime import date, datetime
from decimal import Decimal
from uuid import UUID

def to_json(o):
    if isinstance(o, (date, datetime)):
        return o.isoformat()
    if isinstance(o, (Decimal, UUID)):
        return str(o)
    raise TypeError(f'Object of type {type(o).__name__} is not JSON serializable')

json.dumps(record, default=to_json)
Deterministic cache key
Same data → same text → same hash, regardless of key insertion order.
import hashlib, json
key = hashlib.sha256(json.dumps(params, sort_keys=True, separators=(',', ':')).encode()).hexdigest()

Examples

1. Tuples become arrays
import json json.dumps({'point': (1, 2)})
Returns
'{"point": [1, 2]}'
2. Keys become strings
import json json.dumps({1: 'a', 2.5: 'b', False: 'c', None: 'd'})
Returns
'{"1": "a", "2.5": "b", "false": "c", "null": "d"}'
3. Two keys, one JSON name
import json json.dumps({1: 'int', '1': 'str'})
Returns
'{"1": "int", "1": "str"}'
4. Tuple keys are rejected
import json json.dumps({(1, 2): 'x'})
Returns
TypeError: keys must be str, int, float, bool or None, not tuple
5. skipkeys drops them instead
import json json.dumps({(1, 2): 'x', 'a': 1}, skipkeys=True)
Returns
'{"a": 1}'
6. NaN and Infinity by default
import json json.dumps([float('nan'), float('inf')])
Returns
'[NaN, Infinity]'
7. allow_nan=False refuses them
import json json.dumps([float('nan')], allow_nan=False)
Returns
ValueError: Out of range float values are not JSON compliant: nan
8. A list that contains itself
import json data = [] data.append(data) json.dumps(data)
Returns
ValueError: Circular reference detected

Pitfalls

1. Object of type set is not JSON serializable
JSON has no set. Convert it yourself — sorted() also makes the output order stable, which iterating a set does not.
a set
import json
json.dumps({'tags': {'admin'}})
TypeError: Object of type set is not JSON serializable
sorted(set)
import json
json.dumps({'tags': sorted({'dev', 'admin'})})
'{"tags": ["admin", "dev"]}'
2. Encoding twice
Passing an already-encoded JSON string to dumps encodes it again — as one JSON string full of escaped quotes. Common when a helper already returned JSON text.
dumps(dumps(x))
import json
json.dumps(json.dumps({'a': 1}))
'"{\\"a\\": 1}"'
dumps(x)
import json
json.dumps({'a': 1})
'{"a": 1}'
3. sort_keys with mixed key types
sort_keys sorts the original keys before converting them to strings, so int and str keys cannot be compared.
sort_keys=True
import json
json.dumps({1: 'a', 'b': 2}, sort_keys=True)
TypeError: '<' not supported between instances of 'str' and 'int'
str keys first
import json
data = {1: 'a', 'b': 2}
json.dumps({str(k): v for k, v in data.items()}, sort_keys=True)
'{"1": "a", "b": 2}'
4. Unreadable non-ASCII text
ensure_ascii=True (the default) is valid JSON but escapes every accented letter. Turn it off for files people read; the output is then non-ASCII, so write it as UTF-8.
default
import json
json.dumps({'city': 'Zürich'})
'{"city": "Z\\u00fcrich"}'
ensure_ascii=False
import json
json.dumps({'city': 'Zürich'}, ensure_ascii=False)
'{"city": "Zürich"}'

When to use

Use it
  • You need JSON as a str — HTTP bodies, message queues, database columns, logs
  • Pretty-printing data for a person (indent=2)
  • A deterministic text form of a dict (sort_keys=True) for hashing or diffing
Reach for something else
  • Writing to a file → json.dump(data, f) streams into it
  • Round-tripping Python types (tuples, sets, dates) exactly → pickle, or a schema library
  • Serializing many custom classes → a JSONEncoder subclass keeps default() in one place

Notes

CPython impl
Lib/json/encoder.py; dumps with every argument at its default reuses one module-level JSONEncoder, and encode() runs the C encoder from Modules/_json.c
Floats
Written with float.__repr__, so they round-trip exactly: 0.1 → 0.1, 1e16 → 1e+16
int and bool
True/False become true/false; ints are written with int.__repr__, so an int over 4300 digits raises ValueError (the int-to-str conversion limit)
Dict order
Insertion order unless sort_keys=True

FAQ

json.dumps(data, indent=2) puts every item on its own line with two spaces per level. Add sort_keys=True for a stable key order and ensure_ascii=False to keep non-ASCII text readable.