To write JSON data to a file in Python, open the file in write mode and call json.dump(data, f). Add indent=2 for readable output, and open the file with encoding="utf-8" so names with accents survive:
with open("orders.json", "w", encoding="utf-8") as f:
json.dump(orders, f, indent=2, ensure_ascii=False)
These snippets ran on Python 3.12.5 in a Windows Command Prompt, where encoding mistakes show up fast.
You’ll see json.dump with a list of records, the ensure_ascii setting, the datetime TypeError and its fix, appending to a JSON file, and writing without corrupting the file if something fails.
Write JSON to a file with json.dump()
json.dump() writes straight to a file object; json.dumps() returns a string instead. Here a list of order dictionaries goes to disk and is read back:
import json
from pathlib import Path
orders = [
{"id": 1001, "customer": "Emily Carter", "city": "Austin", "total": 129.99, "paid": True},
{"id": 1002, "customer": "José RamÃrez", "city": "San Antonio", "total": 54.5, "paid": False},
]
with open("orders.json", "w", encoding="utf-8") as f:
json.dump(orders, f, indent=2, ensure_ascii=False)
print(Path("orders.json").read_text(encoding="utf-8"))
print(json.load(open("orders.json", encoding="utf-8"))[1]["customer"])
Output:
[
{
"id": 1001,
"customer": "Emily Carter",
"city": "Austin",
"total": 129.99,
"paid": true
},
{
"id": 1002,
"customer": "José RamÃrez",
"city": "San Antonio",
"total": 54.5,
"paid": false
}
]
José RamÃrez

Python’s True becomes true and None becomes null. The mapping goes the other way too, as shown in converting a Python dict to JSON.
Save a Python dictionary as a JSON file and load it back
A single dict works the same way. The surprise comes when you read it back: JSON object keys are always strings, so integer keys don’t round-trip:
import json
from pathlib import Path
settings = {"store": "Austin #12", "tax_rate": 0.0825, "open_days": ["Mon", "Tue", "Wed"],
1001: "Emily Carter", 1002: "James Wilson"} # int keys
Path("settings.json").write_text(json.dumps(settings, indent=2, sort_keys=False), encoding="utf-8")
loaded = json.loads(Path("settings.json").read_text(encoding="utf-8"))
print(loaded == settings, list(loaded)[-2:]) # int keys came back as strings
fixed = {int(k) if k.isdigit() else k: v for k, v in loaded.items()}
print(fixed == settings)
try:
json.dumps({("TX", "Austin"): 12})
except TypeError as err:
print("TypeError:", err)
Output:
False ['1001', '1002']
True
TypeError: keys must be str, int, float, bool or None, not tuple

Tuple keys can’t be saved at all. Convert them to strings first, or store a list of records instead. Reading JSON text into a dict is covered in converting a JSON string to a dictionary.
Keep accented characters readable with ensure_ascii
By default, json escapes every non-ASCII character. That’s valid JSON, but hard to read:
import json
row = {"customer": "José RamÃrez", "note": "Café ☕"}
print(json.dumps(row)) # default: ensure_ascii=True
print(json.dumps(row, ensure_ascii=False)) # readable, needs a UTF-8 file
print(json.dumps(row, separators=(",", ":"), ensure_ascii=False)) # compact
Output:
{"customer": "Jos\u00e9 Ram\u00edrez", "note": "Caf\u00e9 \u2615"}
{"customer": "José RamÃrez", "note": "Café ☕"}
{"customer":"José RamÃrez","note":"Café ☕"}
With ensure_ascii=False you must write the file as UTF-8, or Windows may fall back to another code page. For spacing and sorting options, see pretty printing JSON in Python.
Why do I get “Object of type datetime is not JSON serializable”?
JSON only knows strings, numbers, booleans, null, arrays and objects. A datetime, Decimal or set stops json.dump():
import json
from datetime import datetime
order = {"id": 1003, "placed": datetime(2026, 10, 6, 9, 30), "total": 89.0}
try:
with open("order.json", "w", encoding="utf-8") as f:
json.dump(order, f)
except TypeError as err:
print("TypeError:", err)
print("left behind:", repr(open("order.json", encoding="utf-8").read()))
Output:
TypeError: Object of type datetime is not JSON serializable
left behind: '{"id": 1003, "placed": '

Pass a default function. json calls it for anything it can’t handle, and you return something it can:
import json
from datetime import date, datetime
from decimal import Decimal
from pathlib import Path
def to_json(value):
if isinstance(value, (datetime, date)):
return value.isoformat()
if isinstance(value, Decimal):
return str(value) # keep every cent exactly
if isinstance(value, set):
return sorted(value)
raise TypeError(f"Can't serialize {type(value).__name__}")
order = {"id": 1003, "placed": datetime(2026, 10, 6, 9, 30), "ship_by": date(2026, 10, 9),
"total": Decimal("89.10"), "tags": {"gift", "express"}}
with open("order.json", "w", encoding="utf-8") as f:
json.dump(order, f, indent=2, default=to_json)
print(Path("order.json").read_text(encoding="utf-8"))
Output:
{
"id": 1003,
"placed": "2026-10-06T09:30:00",
"ship_by": "2026-10-09",
"total": "89.10",
"tags": [
"express",
"gift"
]
}

The failed run above left a partial order.json behind, since the file was opened before the error. The safe-write pattern below avoids that. Before storing timestamps, read naive vs aware datetime in Python so the ISO strings carry a time zone when they need one.
Append data to a JSON file
A JSON file holds one value, so you can’t just append to it. Either load it, change it and rewrite it, or switch to JSON Lines: one JSON object per line, which works with append mode:
import json
from pathlib import Path
Path("events.jsonl").unlink(missing_ok=True)
def log_event(event):
with open("events.jsonl", "a", encoding="utf-8") as f: # append one line per record
f.write(json.dumps(event) + "\n")
log_event({"user": "olivia", "action": "login", "at": "2026-10-06T08:01:00"})
log_event({"user": "james", "action": "checkout", "amount": 42.75})
log_event({"user": "olivia", "action": "logout"})
print(Path("events.jsonl").read_text(encoding="utf-8"))
events = [json.loads(line) for line in open("events.jsonl", encoding="utf-8")]
print(len(events), "events; checkouts:", sum(e.get("amount", 0) for e in events))
Output:
{"user": "olivia", "action": "login", "at": "2026-10-06T08:01:00"}
{"user": "james", "action": "checkout", "amount": 42.75}
{"user": "olivia", "action": "logout"}
3 events; checkouts: 42.75

I use JSON Lines for logs and exports that grow over time. If you’re writing other text formats, see writing a list to a file in Python.
Write a JSON file safely with os.replace()
If dump() fails halfway, the old file is already truncated. Write to a temporary file in the same folder, then swap it in with os.replace():
import json
import os
import tempfile
from pathlib import Path
def write_json_atomic(path, data):
path = Path(path)
fd, tmp = tempfile.mkstemp(dir=path.parent, suffix=".tmp")
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
f.flush()
os.fsync(f.fileno())
os.replace(tmp, path) # swap in one step
except BaseException:
os.remove(tmp)
raise
write_json_atomic("settings.json", {"theme": "dark", "currency": "USD"})
try:
write_json_atomic("settings.json", {"theme": "light", "bad": {1, 2}})
except TypeError as err:
print("write failed:", err)
print("file still holds:", Path("settings.json").read_text(encoding="utf-8").replace("\n", " "))
Output:
write failed: Object of type set is not JSON serializable
file still holds: { "theme": "dark", "currency": "USD" }
The second write fails on the set, and the original settings survive untouched. To replace an existing file on purpose, see overwriting a file in Python.
JSON writing options compared
| Need | Code |
|---|---|
| Write to a file | json.dump(data, f) |
| Get a string | json.dumps(data) |
| Readable file | indent=2, ensure_ascii=False + encoding="utf-8" |
| datetime / Decimal / set | default=to_json |
| Add records over time | JSON Lines with mode "a" |
| Never leave a broken file | Temp file + os.replace() |
Working with JSON regularly? These guides are next:
- Write a dictionary to a text file in Python
- Work with JSON data in Python
- Convert a dictionary to JSON in Python
- Convert a pandas DataFrame to JSON
Frequently asked questions
How do I write JSON data to a file in Python?
Open the file with open(path, "w", encoding="utf-8") and call json.dump(data, f, indent=2).
Why do my integer dictionary keys come back as strings?
JSON object keys are always strings. Convert them back after loading, for example with int(k).
How do I fix “Object of type datetime is not JSON serializable”?
Pass default= a function that returns value.isoformat() for dates.
How do I append to a JSON file?
Load, modify and rewrite the whole file, or use JSON Lines and append one json.dumps() line per record.
Why are my accented characters written as \u00e9?
ensure_ascii is True by default. Set ensure_ascii=False and open the file as UTF-8.
Where is json.dump documented?
See json.dump() in the Python docs.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn