JSON (JavaScript Object Notation) is the most widely used data interchange format on the modern web. Nearly every REST API returns JSON, configuration files use JSON, and NoSQL databases like MongoDB store data in this format. Python offers native and extremely powerful JSON support through the json module, part of the standard library.
In this complete guide, you will learn everything about manipulating JSON data with Python: from basic serialization with json.dumps() and json.loads() to advanced techniques like custom encoders, JSON Schema validation, and REST API integration. Let's get started!
What is JSON?
JSON is a lightweight text format for storing and transporting structured data. It was originally specified by Douglas Crockford at JSON.org and later standardized by RFC 7159. Its syntax is simple and readable for both humans and machines.
JSON supports only six data types:
- String — sequence of characters in double quotes
- Number — integers or floating-point decimals
- Boolean —
trueorfalse - Null — null value (
null) - Array — ordered list of values in brackets
[] - Object — collection of key/value pairs in braces
{}
{
"name": "Python",
"version": 3.12,
"paradigms": ["Object-Oriented", "Functional", "Imperative"],
"typing": "dynamic",
"open_source": true,
"creator": null
}
According to MDN Web Docs, JSON stands out for its simplicity and ubiquity on the web, being natively supported by all modern programming languages.
The Python json Module
Python includes the json module as part of its standard library. This means you don't need to install anything — just import it and start using it. The official json module documentation is the ideal starting point for in-depth reference.
import json
The module provides four main functions that form the foundation of all JSON manipulation in Python:
json.dumps()— converts a Python object into a JSON stringjson.loads()— converts a JSON string into a Python objectjson.dump()— writes a Python object directly to a JSON filejson.load()— reads a JSON file and converts it into a Python object
json.dumps() — Serializing Python to JSON
The json.dumps() function serializes a Python object into a JSON string. The conversion table follows the standard mapping:
dict→Object{}list,tuple→Array[]str→Stringint,float→NumberTrue→trueFalse→falseNone→null
import json
data = {
"language": "Python",
"created_in": 1991,
"types": ["int", "float", "str", "list", "dict"],
"interpreted": True,
"author": None
}
json_string = json.dumps(data)
print(json_string)
Output: {"language": "Python", "created_in": 1991, "types": ["int", "float", "str", "list", "dict"], "interpreted": true, "author": null}
Notice how True becomes true and None becomes null automatically, following the JSON standard.
Advanced dumps() Parameters
json.dumps() offers several parameters to control the output:
import json
data = {"name": "Python", "version": 3.12, "features": ["simple", "powerful"]}
indent — formats with indentation for readability
print(json.dumps(data, indent=2))
sort_keys — sorts keys alphabetically
print(json.dumps(data, indent=2, sort_keys=True))
ensure_ascii — if False, allows Unicode characters
print(json.dumps({"name": "João"}, ensure_ascii=False))
Output: {"name": "João"}
separators — customizes separators (removes spaces)
print(json.dumps(data, separators=(",", ":")))
Output: {"name":"Python","version":3.12,"features":["simple","powerful"]}
The ensure_ascii=False parameter is essential when working with Portuguese or any language that uses accented characters, as explained in the Real Python JSON tutorial.
json.loads() — Converting JSON to Python
The json.loads() function does the reverse: it takes a JSON string and converts it into a Python object.
import json
json_string = '{"name": "Python", "version": 3.12, "interpreted": true, "author": null}'
data = json.loads(json_string)
print(data)
Output: {'name': 'Python', 'version': 3.12, 'interpreted': True, 'author': None}
print(type(data))
Output: <class 'dict'>
The conversion respects the reverse mapping: true becomes True, null becomes None, and JSON strings become Python strings. The result is always a Python dictionary when the source JSON is an object.
json.dump() and json.load() — Working with Files
The json.dump() and json.load() functions work directly with files, avoiding the need for intermediate strings. This topic ties in with our guide on File Manipulation in Python: TXT, CSV, and JSON.
import json
Writing JSON to a file
data = {
"name": "Python",
"year": 1991,
"frameworks": ["Django", "Flask", "FastAPI"]
}
with open("data.json", "w", encoding="utf-8") as file:
json.dump(data, file, indent=2, ensure_ascii=False)
Reading JSON from a file
with open("data.json", "r", encoding="utf-8") as file:
loaded_data = json.load(file)
print(loaded_data["name"]) # Output: Python
Always use utf-8 encoding when working with JSON files to ensure compatibility with accented and special characters.
Serializing Custom Python Objects
By default, the json module does not know how to serialize custom class objects. Try running the code below and you will get a TypeError:
import json
class Person:
def init(self, name, age):
self.name = name
self.age = age
p = Person("Anna", 30)
print(json.dumps(p)) # TypeError: Object of type Person is not JSON serializable
There are two main approaches to solve this.
Method 1: Using a Custom JSONEncoder
Create a subclass of json.JSONEncoder and override the default() method. The official JSONEncoder documentation provides all the details for this approach.
import json
from datetime import datetime
class Person:
def init(self, name, age):
self.name = name
self.age = age
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age, "_type": "Person"}
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
p = Person("Anna", 30)
now = datetime.now()
print(json.dumps({"person": p, "now": now}, cls=CustomEncoder, indent=2))
Method 2: Using Pydantic
Pydantic is a library that provides data validation and native JSON serialization. It is widely used with FastAPI and is the recommended approach for professional projects.
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
p = Person(name="Anna", age=30)
print(p.model_dump_json(indent=2))
Output: {"name": "Anna", "age": 30}
The model_dump_json() method from Pydantic already returns a valid JSON string, solving serialization elegantly and safely.
Handling Errors and Exceptions
When working with JSON data, especially from external sources, it is essential to handle parsing errors. The json module raises specific exceptions that should be caught:
import json
def process_json(text):
try:
data = json.loads(text)
return data
except json.JSONDecodeError as e:
print(f"Error decoding JSON: {e}")
print(f"Error position: line {e.lineno}, column {e.colno}")
return None
Invalid JSON
invalid_json = '{"name": "Python", version: 3.12}'
result = process_json(invalid_json)
Output: Error decoding JSON: ...
Valid JSON
valid_json = '{"name": "Python"}'
result = process_json(valid_json)
print(result)
Output: {'name': 'Python'}
Always validate incoming JSON before processing it. Combining try/except with json.JSONDecodeError ensures your application does not crash when receiving malformed data.
Validation with JSON Schema
To ensure JSON follows a specific structure, you can use JSON Schema. This specification defines formal contracts for JSON document structure, essential for APIs and system integrations.
from jsonschema import validate, ValidationError
schema = {
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 1},
"age": {"type": "integer", "minimum": 0},
"email": {"type": "string", "format": "email"}
},
"required": ["name", "email"]
}
valid_data = {"name": "Anna", "age": 30, "email": "[email protected]"}
validate(instance=valid_data, schema=schema) # OK, no exception
invalid_data = {"name": "", "email": "invalid"}
try:
validate(instance=invalid_data, schema=schema)
except ValidationError as e:
print(f"Validation error: {e.message}")
While the jsonschema library needs to be installed separately (pip install jsonschema), it is extremely useful for validating API payloads, configuration files, and any JSON data that requires a predictable structure.
JSON and REST APIs
JSON is the standard input and output format for most modern REST APIs. When you make an HTTP request to an API, the response almost always comes back as JSON. Here is how to consume and send JSON using the requests library:
import json
import requests
Consuming an API that returns JSON
response = requests.get("https://api.github.com/users/python")
data = response.json() # Equivalent to json.loads(response.text)
print(f"Public repos: {data['public_repos']}")
Sending JSON to an API
payload = {"title": "New Post", "body": "JSON with Python"}
headers = {"Content-Type": "application/json"}
response = requests.post(
"https://jsonplaceholder.typicode.com/posts",
data=json.dumps(payload),
headers=headers
)
print(response.json())
To fully master API consumption, check out the complete guide on Python Requests for HTTP Requests.
FastAPI, one of the most popular Python web frameworks, uses Pydantic to validate and serialize JSON automatically. The FastAPI JSON Encoder documentation shows how the framework handles custom types transparently.
Best Practices and Performance
When working with JSON in Python, follow these recommendations:
- Always use
ensure_ascii=Falsewhen dealing with accented or Unicode content - Use
indentonly for config files — in production, omit it to reduce payload size - Use
separators=(",", ":")in APIs to minimize JSON payload - Prefer Pydantic or dataclasses for object serialization in larger projects
- Validate data with JSON Schema when the structure must be guaranteed
- Handle exceptions with
json.JSONDecodeErrorwhen processing external data
For projects requiring maximum performance, consider alternatives like orjson (written in Rust) or ujson. Python's native json module, however, is sufficient for the vast majority of use cases and has the advantage of requiring no external dependencies.
The W3Schools Python JSON tutorial offers additional examples and practical exercises to reinforce your learning.
Conclusion
JSON and Python form a powerful and ubiquitous combination in modern software development. The json module from the standard library provides all the tools needed to serialize, deserialize, read, and write JSON data in just a few lines of code.
In this guide, you learned:
- The fundamentals of the JSON format and its data types
- The four main functions:
dumps(),loads(),dump(),load() - How to serialize custom Python objects with JSONEncoder and Pydantic
- How to handle parsing errors and validate structures with JSON Schema
- How to integrate JSON with REST APIs using the requests library
- Best practices for performance and security
With this knowledge, you are ready to manipulate JSON data in any Python project — whether a web application, an automation script, a REST API, or a data pipeline. To go even deeper, explore the official documentation and practice with real data from public APIs.