Python's json module, part of the Python standard library, lets you read and write JSON (JavaScript Object Notation) files and strings. JSON is the most common data format for APIs, configuration files, and data exchange between systems, and it is human-readable, language-independent, and maps naturally to Python's built-in types.
import json
data = '{"name": "Maya", "score": 42, "active": true}'
parsed = json.loads(data)
print(parsed["name"]) # Maya
print(type(parsed["score"])) # <class 'int'>json.loads() parses a JSON string into a Python dictionary. JSON true becomes Python True, and JSON numbers become Python int or float based on whether they have a decimal point.
JSON type mapping
Python and JSON use different type names, but the mapping is straightforward.
| JSON type | Python type |
|---|---|
| object | dict |
| array | list |
| string | str |
| number (integer) | int |
| number (real) | float |
| true | True |
| false | False |
| null | None |
The json module handles these conversions automatically when reading and writing.
Reading JSON from a string
Use json.loads() (load string) to parse JSON from a string variable.
import json
response = '{"items": [{"id": 1, "label": "apple"}, {"id": 2, "label": "banana"}]}'
data = json.loads(response)
for item in data["items"]:
print(item["label"])The loop prints one line per item in the array, apple then banana, because iterating a parsed JSON array works exactly like iterating any other Python list. json.loads(response) turns the string into a Python dict. You can then access nested keys and iterate over arrays with normal Python syntax.
Reading JSON from a file
Use json.load() to read JSON directly from a file object. The file must be opened in text mode.
import json
with open("config.json") as file:
config = json.load(file)
print(config.get("theme", "light")) # darkAssuming config.json contains {"theme": "dark", "version": 2}, json.load(file) reads and parses the file in one step. The with statement ensures the file is closed after reading, as covered in using the with statement for files.
Writing JSON to a string
Use json.dumps() (dump string) to convert a Python object to a JSON string.
import json
user = {
"name": "Maya",
"active": True,
"tags": ["python", "beginner"],
"score": None,
}
print(json.dumps(user))Calling dumps on the dictionary produces a single compact line with the keys and values encoded as valid JSON syntax, ready to send over a network or write to disk:
{"name": "Maya", "active": true, "tags": ["python", "beginner"], "score": null}json.dumps(user) converts the Python dict to a compact JSON string. Python True becomes JSON true and Python None becomes JSON null.
Writing JSON to a file
Use json.dump() to write JSON directly to a file object.
import json
settings = {"theme": "dark", "font_size": 14, "autosave": True}
with open("settings.json", "w") as file:
json.dump(settings, file)json.dump(settings, file) writes the dictionary as JSON to settings.json. The file is created if it does not exist or overwritten if it does.
Formatting JSON output for readability
Compact JSON is hard to read. Use indent to add line breaks and spacing.
import json
data = {"cities": ["Paris", "Tokyo", "Nairobi"], "count": 3}
print(json.dumps(data, indent=2))Passing indent=2 tells dumps to add a newline and two spaces of indentation for every level of nesting, turning the single compact line into a readable, multi-line structure that mirrors how the data is organized:
{
"cities": [
"Paris",
"Tokyo",
"Nairobi"
],
"count": 3
}indent=2 adds two spaces per nesting level. Use this for configuration files, debug output, or any JSON meant for human readers.
Use sort_keys=True to alphabetize keys for consistent output:
print(json.dumps(data, indent=2, sort_keys=True))Combine indent with ensure_ascii=False if your data contains non-ASCII characters like accented letters or emoji, since the default settings would otherwise escape every one of those characters into unreadable numeric codes:
import json
message = {"text": "Café résumé"}
print(json.dumps(message, ensure_ascii=False)) # {"text": "Café résumé"}Without ensure_ascii=False, the accented characters would be escaped as \u00e9 sequences.
Handling non-serializable types
JSON only supports dicts, lists, strings, numbers, booleans, and None. If your data contains Python objects like datetime, Decimal, or custom classes, json.dumps raises a TypeError.
import json
from datetime import datetime
data = {"timestamp": datetime.now()}
json.dumps(data)Running this raises an error immediately, because the json module has no built-in rule for turning a datetime object into JSON text on its own:
TypeError: Object of type datetime is not JSON serializableThe simplest fix is to convert the value to a string before serialization, since a plain string is one of the types the json module already knows how to encode without any extra configuration:
import json
from datetime import datetime
data = {"timestamp": datetime.now().isoformat()}
print(json.dumps(data)) # {"timestamp": "2026-07-12T14:30:05.123456"}Converting every field by hand does not scale once several different objects need the same treatment. For more complex cases, provide a custom default function that dumps calls automatically whenever it meets a type it cannot serialize on its own:
import json
from datetime import datetime
def serialize(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Type {type(obj)} not serializable")
data = {"created_at": datetime.now()}
print(json.dumps(data, default=serialize))The default function is called for every value that json.dumps cannot handle. Return a serializable representation or raise TypeError.
Handling malformed JSON
When parsing JSON from external sources like API responses, the input might be malformed. Always handle json.JSONDecodeError.
import json
raw = '{"name": "Maya", "score": 42,}' # trailing comma
try:
data = json.loads(raw)
except json.JSONDecodeError as err:
print(f"Invalid JSON: {err}")The trailing comma after 42 is not allowed in JSON, so parsing fails and the except block catches the resulting decode error and prints a readable message instead of crashing the program:
Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 30 (char 29)json.JSONDecodeError includes the line, column, and character position where parsing failed. This is helpful for debugging API integrations or user-supplied JSON.
Practical example: reading and filtering API data
A common pattern is to read a JSON file, filter its contents, and write the result.
import json
with open("products.json") as file:
products = json.load(file)
in_stock = [p for p in products if p.get("stock", 0) > 0]
with open("in_stock.json", "w") as file:
json.dump(in_stock, file, indent=2)
print(f"Found {len(in_stock)} products in stock.")The script reads a list of products, filters to items with stock above zero using a list comprehension, and writes the filtered list to a new file with readable formatting.
Common mistakes
Using single quotes in JSON. JSON requires double quotes for strings and keys. Python's json.loads rejects single-quoted strings. Use json.dumps to generate valid JSON, and never hand-write JSON with single quotes.
Forgetting to open files in text mode. json.load and json.dump require text-mode file objects. Opening a file with "rb" or "wb" (binary mode) causes a TypeError. Use "r" and "w" by default.
Parsing the same JSON string twice. If json.loads succeeds, the result is already a Python object. Calling json.loads on it again will fail because it is no longer a string.
Passing a string to json.load. json.load expects a file object, not a string. Use json.loads for strings.
Rune AI
Key Insights
- Use
json.load(file)to read JSON from a file andjson.loads(string)to parse a JSON string. - Use
json.dump(obj, file)to write JSON to a file andjson.dumps(obj)to produce a JSON string. - JSON maps dicts, lists, strings, numbers, booleans, and None between Python and JSON automatically.
- Use
indentfor readable output andensure_ascii=Falsefor non-ASCII characters. - Provide a
defaultfunction tojson.dumpsto handle datetime and other non-serializable types. - Catch
json.JSONDecodeErrorwhen parsing untrusted or potentially malformed JSON input.
Frequently Asked Questions
What JSON types does Python support?
Why do I get a TypeError when writing a datetime to JSON?
What is the difference between json.load and json.loads?
Conclusion
The json module is the standard way to work with JSON in Python. Use json.load and json.dump for files, json.loads and json.dumps for strings. When you encounter types that JSON cannot handle natively, write a custom encoder or convert the values before serialization.
More in this topic
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Python `math` Module Explained
Learn how to use the Python math module for square roots, rounding, trigonometry, logarithms, and mathematical constants.
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.