JSON Serialization in Python — Complete Guide
Python's built-in json module handles the basics well, but the moment you try to serialize a datetime, a Decimal, or a custom class instance, you hit TypeError: Object of type X is not JSON serializable. This guide covers the module's core functions and exactly how to handle the types it does not support natively.
The Basics: dumps, loads, dump, load
import json
data = {"name": "Priya Sharma", "age": 29, "active": True}
# Python object -> JSON string
json_string = json.dumps(data)
print(json_string) # '{"name": "Priya Sharma", "age": 29, "active": true}'
# JSON string -> Python object
parsed = json.loads(json_string)
print(parsed["name"]) # Priya Sharma
# Write directly to a file
with open("user.json", "w") as f:
json.dump(data, f, indent=2)
# Read directly from a file
with open("user.json") as f:
loaded = json.load(f)The "Not JSON Serializable" Error
from datetime import datetime
data = {"name": "Priya", "created_at": datetime.now()}
json.dumps(data)
# TypeError: Object of type datetime is not JSON serializable
# The json module only knows how to convert: dict, list, tuple, str,
# int, float, bool, and None. Everything else needs help.Fix 1: The default Parameter
The simplest fix — pass a function that converts unknown types to something JSON-compatible:
from datetime import datetime
from decimal import Decimal
def json_default(obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Decimal):
return float(obj)
raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")
data = {
"name": "Priya",
"created_at": datetime.now(),
"balance": Decimal("1499.50")
}
print(json.dumps(data, default=json_default))
# {"name": "Priya", "created_at": "2026-07-11T14:30:00.123456", "balance": 1499.5}Fix 2: A Custom JSONEncoder Class
For reuse across a codebase, subclass json.JSONEncoder instead of passing default everywhere:
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Decimal):
return float(obj)
if hasattr(obj, "__dict__"):
return obj.__dict__ # serialize simple custom class instances
return super().default(obj)
class Order:
def __init__(self, id, total):
self.id = id
self.total = total
order = Order(id=501, total=Decimal("1499.50"))
print(json.dumps(order, cls=CustomEncoder))
# {"id": 501, "total": 1499.5}Deserializing Back into Custom Types
Deserialization is one-directional by default — dates come back as plain strings. Use object_hook to reconstruct richer types on load:
def date_hook(d):
for key, value in d.items():
if key.endswith("_at"):
try:
d[key] = datetime.fromisoformat(value)
except (ValueError, TypeError):
pass
return d
json_string = '{"name": "Priya", "created_at": "2026-07-11T14:30:00"}'
result = json.loads(json_string, object_hook=date_hook)
print(type(result["created_at"])) # <class 'datetime.datetime'>Quick Reference: Common Type Conversions
- datetime / date — convert with
.isoformat(), parse back withdatetime.fromisoformat() - Decimal — convert with
float()orstr()to avoid precision loss for currency - set — convert with
list(); JSON has no set type - bytes — convert with
.decode('utf-8')or base64-encode binary data - Enum — convert with
.valueor.name - Custom classes — implement
__dict__access or ato_dict()method used in your encoder
Frequently Asked Questions
This error occurs when json.dumps encounters a Python object it does not know how to convert, such as datetime, Decimal, or a custom class instance. Fix it by passing a default function or a custom JSONEncoder subclass that converts the object to a JSON-compatible type like a string or number.
Convert the datetime object to an ISO 8601 string using .isoformat() before serializing, either manually or via a default function passed to json.dumps, since the json module has no built-in support for datetime objects.
Yes. Dev Brains AI JSON Formatter validates and pretty-prints JSON output from any language, including Python, directly in your browser.