How to create a JSON file in Python
Learn how to create a JSON file in Python. This guide covers various methods, tips, real-world applications, and common error debugging.

JSON is a lightweight format perfect for data exchange. In Python, you can create JSON files to store data structures or communicate with web APIs. The built-in json module simplifies this process.
In this article, we'll walk you through techniques to write JSON files. We'll cover practical tips, explore real-world applications, and offer advice to debug common issues you might face.
Creating a JSON file with json.dump()
import json
data = {"name": "John", "age": 30, "city": "New York"}
with open("data.json", "w") as file:
json.dump(data, file)--OUTPUT--# No output, but a data.json file is created with content:
# {"name": "John", "age": 30, "city": "New York"}
The json.dump() function is your go-to for writing Python objects directly to a file in JSON format. It takes two main arguments: the data you want to serialize—in this case, the data dictionary—and the file object to write to.
Using the with open("data.json", "w") as file: syntax is a best practice. It ensures the file is automatically closed after the block is executed, which prevents data corruption. The "w" mode specifies that you're opening the file for writing, which will create data.json or overwrite it if it already exists.
Basic techniques for JSON file creation
Beyond writing directly to a file with json.dump(), you can gain more flexibility by manipulating JSON as a string and handling more complex data structures.
Using json.dumps() to generate JSON strings
import json
data = {"name": "Alice", "age": 25, "city": "Boston"}
json_string = json.dumps(data)
with open("data_string.json", "w") as file:
file.write(json_string)--OUTPUT--# No output, but a data_string.json file is created with content:
# {"name": "Alice", "age": 25, "city": "Boston"}
The json.dumps() function—notice the “s” for “string”—converts a Python object into a JSON formatted string. This approach gives you more control. Instead of writing directly to a file, you get a string variable that you can manipulate, log, or send over a network. Once you have the string, you can write it to a file using the standard file.write() method.
Working with nested data structures
import json
user = {
"name": "Bob",
"address": {"street": "123 Main St", "city": "Chicago"},
"hobbies": ["reading", "swimming", "coding"]
}
with open("nested_data.json", "w") as file:
json.dump(user, file)--OUTPUT--# No output, but a nested_data.json file is created with content:
# {"name": "Bob", "address": {"street": "123 Main St", "city": "Chicago"}, "hobbies": ["reading", "swimming", "coding"]}
The json module’s real power shines when you’re working with complex data. It automatically handles nested Python objects, so you don’t need to flatten your data structures before serializing them. The json.dump() function recursively traverses your data, ensuring the output file accurately reflects the original structure.
- Python dictionaries, like the
addressobject, are converted into JSON objects. - Python lists, such as the
hobbieslist, become JSON arrays.
Handling file encoding options
import json
data = {"name": "Carlos", "description": "Loves café au lait ☕"}
with open("unicode_data.json", "w", encoding="utf-8") as file:
json.dump(data, file, ensure_ascii=False)--OUTPUT--# No output, but a unicode_data.json file is created with proper UTF-8 encoding:
# {"name": "Carlos", "description": "Loves café au lait ☕"}
When your data includes special characters or emojis, you'll need to handle file encoding properly, just like managing system dependencies in Python projects. By default, the json module escapes non-ASCII characters, which can make your JSON file difficult to read.
- Use
encoding="utf-8"in theopen()function to support international characters. - Set
ensure_ascii=Falseinjson.dump()to write characters like “é” or “☕” directly, rather than as escape codes.
Together, these settings ensure your JSON file is saved correctly and stays human-readable.
Advanced JSON file handling
Now that you can write basic JSON files, you can explore advanced options like the indent parameter to improve readability and handle custom objects.
Creating formatted JSON with indent and sort_keys
import json
data = {"z": 1, "b": 2, "a": 3, "nested": {"x": 1, "y": 2}}
with open("formatted.json", "w") as file:
json.dump(data, file, indent=4, sort_keys=True)--OUTPUT--# No output, but a formatted.json file is created with content:
# {
# "a": 3,
# "b": 2,
# "nested": {
# "x": 1,
# "y": 2
# },
# "z": 1
# }
When you need to read or debug a JSON file, formatting is your best friend. The json.dump() function includes two helpful parameters that clean up the output, making it much easier to scan visually.
- The
indentparameter pretty-prints the JSON. Settingindent=4adds newlines and uses four spaces for each level of nesting, creating a clear visual structure. - Setting
sort_keys=Trueorganizes the keys in your dictionaries alphabetically. This creates a predictable order, which is great for comparing files or just finding what you're looking for.
Custom object serialization with the default parameter
import json
from datetime import datetime
def serialize_datetime(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError("Type not serializable")
data = {"name": "Event", "timestamp": datetime.now()}
with open("custom_objects.json", "w") as file:
json.dump(data, file, default=serialize_datetime)--OUTPUT--# No output, but a custom_objects.json file is created with content:
# {"name": "Event", "timestamp": "2023-04-15T14:30:45.123456"}
The json module can't serialize every Python object out of the box. If you try to dump a complex type like a datetime object, you'll get a TypeError. The default parameter in json.dump() provides a clean way to handle this by letting you define a custom serialization function.
- You pass a function—in this case,
serialize_datetime—to thedefaultparameter. - When
json.dump()encounters a type it can't handle, it calls your function with that object. - The function then converts the object into a JSON-compatible format, like a string from
isoformat().
Using JSONEncoder for complex serialization
import json
from datetime import datetime
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return {"__datetime__": obj.isoformat()}
return super().default(obj)
data = {"event": "Meeting", "when": datetime.now()}
with open("encoder.json", "w") as file:
json.dump(data, file, cls=CustomEncoder, indent=2)--OUTPUT--# No output, but an encoder.json file is created with content:
# {
# "event": "Meeting",
# "when": {
# "__datetime__": "2023-04-15T14:30:45.123456"
# }
# }
For more structured or reusable serialization logic, you can create a custom class that inherits from json.JSONEncoder. This approach is more powerful than using the default parameter, especially when you need to handle multiple custom types.
- You override the
default()method to define how to convert specific objects, likedatetime, into a JSON-serializable format. - In the example, the
datetimeobject becomes a dictionary. This is a common pattern that helps preserve type information for later use. - You then pass your custom encoder class to
json.dump()using theclsparameter.
Move faster with Replit
Replit is an AI-powered development platform where all Python dependencies pre-installed, so you can skip setup and start coding instantly. While the techniques in this article are powerful, you can move from learning individual functions to building complete applications with Agent 4. It handles writing code, connecting to databases, and deploying your app, all from a simple description.
Instead of piecing together code snippets, you can describe the final product you want to build, and the Agent will generate it for you. For example, you could build:
- A configuration file generator that converts form inputs into a structured, indented JSON file for a web application.
- An API data exporter that serializes complex objects, like user profiles with
datetimetimestamps, into clean JSON for reporting dashboards. - A data migration tool that reads nested JSON from one source, transforms its structure, and writes it to a new file for system integration.
Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.
Common errors and challenges
Writing JSON files is straightforward, but a few common errors can trip you up along the way.
The most frequent issue is a TypeError. This error pops up when you try to serialize an object that the json module doesn't natively understand, such as a datetime object or a custom class. As we've covered, you can resolve this by using the default parameter or a custom JSONEncoder to define how to convert the object into a JSON-compatible format.
Another common pitfall is an UnsupportedOperation error, which almost always points to opening the file in the wrong mode. If you try to use json.dump() on a file opened in read mode ("r"), Python will stop you. Always ensure you're using write mode ("w") to avoid this simple mistake.
Finally, if your output file is filled with escape codes like \u2615 instead of the actual characters, you're dealing with an encoding problem. To fix this and make your JSON human-readable, open the file with encoding="utf-8" and pass ensure_ascii=False to the json.dump() function.
Handling non-serializable types with json.dump()
You'll inevitably run into a TypeError when trying to serialize objects that aren't natively supported by the json module. For instance, a datetime object will cause json.dump() to fail. The code below shows this common error in action.
import json
from datetime import datetime
event = {"name": "Conference", "date": datetime.now()}
with open("event.json", "w") as file:
json.dump(event, file)
The json.dump() function fails because the datetime object isn't a standard data type it recognizes. To fix this, you need to tell the function how to convert it. The following example shows how to do this.
import json
from datetime import datetime
event = {"name": "Conference", "date": datetime.now()}
event["date"] = event["date"].isoformat()
with open("event.json", "w") as file:
json.dump(event, file)
The solution is to manually convert the non-serializable object into a string before calling json.dump(). In this case, the isoformat() method turns the datetime object into a standard string that JSON can process. This direct approach is perfect for quick, one-off fixes where you don't need a reusable serialization function. It’s a simple way to handle isolated data types without adding complexity to your code.
Fixing incorrect file modes with json.dump()
It's easy to accidentally open a file in the wrong mode. The json.dump() function requires a file to be opened for writing. If you use read mode ("r") instead, Python will stop you with an UnsupportedOperation error. See what happens below.
import json
user = {"name": "John", "age": 30}
with open("user.json", "r") as file:
json.dump(user, file)
The file is opened in read-only mode ("r"), but json.dump() needs write access. This conflict is what triggers the error. See how the corrected code below resolves this mismatch.
import json
user = {"name": "John", "age": 30}
with open("user.json", "w") as file:
json.dump(user, file)
The fix is simple: change the file mode from "r" (read) to "w" (write). The json.dump() function needs permission to write data, which it doesn't get when a file is opened in read mode. Using "w" tells Python you intend to write to the file, resolving the UnsupportedOperation error. It’s a common mistake to watch for whenever you're serializing data and saving it to a file.
Handling special characters encoding in json.dump()
When your data includes special characters like “é” or “€”, you might find your JSON output isn't what you expected. By default, json.dump() escapes these characters, turning them into unreadable codes. The code below shows what happens in this common scenario.
import json
message = {"text": "Café au lait costs €5"}
with open("message.json", "w") as file:
json.dump(message, file)
Because json.dump() defaults to ensuring all characters are ASCII-compatible, it converts special symbols into escape codes. This results in a file that isn't easily readable. See how the corrected code below addresses this.
import json
message = {"text": "Café au lait costs €5"}
with open("message.json", "w", encoding="utf-8") as file:
json.dump(message, file, ensure_ascii=False)
The fix involves two key adjustments. First, open the file using encoding="utf-8" to ensure it supports a wide range of characters.
Next, pass ensure_ascii=False to the json.dump() function. This tells the function to write characters like “é” and “€” directly instead of converting them to escape codes. These settings work together to keep your JSON human-readable, which is crucial when dealing with international text or currency symbols.
Real-world applications
Now that you can troubleshoot common issues, you can apply these skills to tasks like storing configurations and exporting data through traditional programming or vibe coding.
Storing application configuration settings with json.dump()
JSON is an excellent format for configuration files, and you can use json.dump() to save settings like theme preferences and font sizes in a human-readable structure.
import json
app_config = {
"theme": "dark",
"font_size": 12,
"auto_save": True,
"recent_files": []
}
with open("app_config.json", "w") as config_file:
json.dump(app_config, config_file, indent=2)
This example shows how to save a Python dictionary to a file using the json module. The json.dump() function takes the app_config dictionary and writes it to a file named app_config.json. Using the with open(...) syntax is a good practice because it ensures the file is closed automatically after writing.
- The dictionary is serialized into a JSON formatted string and saved.
- The
indent=2argument formats the output with two-space indentation, making the file's structure easy to inspect visually during development.
Creating a simple data export tool with json.dump()
The json.dump() function is also ideal for building simple data export tools that process information before saving it to a file.
import json
from datetime import datetime
sales_data = [
{"product": "Laptop", "units": 5, "price": 1200.00},
{"product": "Monitor", "units": 10, "price": 300.00},
{"product": "Keyboard", "units": 15, "price": 80.00}
]
# Calculate total sales for each product
for item in sales_data:
item["total"] = item["units"] * item["price"]
filename = f"sales_export_{datetime.now().strftime('%Y%m%d')}.json"
with open(filename, "w") as export_file:
json.dump({"sales": sales_data, "generated_at": datetime.now().isoformat()}, export_file, indent=2)
This script processes a list of sales records before exporting them. It first enriches the original sales_data on the fly by calculating a new total value for each product and adding it to the corresponding dictionary.
- A unique filename is generated using the current date, which ensures daily exports don’t overwrite each other.
- The final JSON output wraps the processed data under a
saleskey and adds agenerated_attimestamp, providing useful metadata for the export.
Get started with Replit
Turn what you've learned into a real tool with Replit Agent. Describe what you want, like “a tool that saves form inputs to a formatted JSON config file” or “an exporter for user data with timestamps.”
Replit Agent writes the code, tests for errors, and deploys your application. Start building with Replit.
Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.
Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.



