Changing a stored setting may mean reading its JSON file in Python. Python’s json module reads that file into Python values that a script can edit and save as JSON.
I’ll explain how Python represents JSON data, then show how to update a file.
TL;DR: Read, Modify, and Save a JSON File
For a small JSON document, load it into Python, change the returned dictionary or list, then write the complete value back to disk. I used a temporary file and os.replace() in the tested example so a shorter result cannot leave old characters at the end.
- Use json.load() and json.dump() with file objects.
- Use json.loads() and json.dumps() with JSON text strings.
- Change Python data, not the original JSON text in memory.
- Read the saved file again to check the result.
What Is JSON in Python?
JSON is a text format for storing one structured value or exchanging data between programs. Python’s built-in json module converts that text into Python values and converts supported Python values back to JSON.
JSON is a text format, not executable Python code. Loading it parses one structured value without running statements from the file.
| JSON value | Python value |
|---|---|
| Object | dict |
| Array | list |
| String | str |
| Number | int or float |
| true or false | True or False |
| null | None |
The four common functions split into two pairs. The functions with a final s work with a string in memory, while the versions without it work with a file-like object. A file-like object is a value that can read or write text, such as the object returned by open().
| Function | Input or destination | Result |
|---|---|---|
| json.load(file) | Open file object | Python value |
| json.loads(text) | JSON string | Python value |
| json.dump(value, file) | Python value and open file object | Writes JSON text |
| json.dumps(value) | Python value | JSON string |
Inspect the returned top-level type before treating a JSON document as an object. Decoding a file reads the complete value before code can inspect one item. I chose load() and dump() in the example because they keep the file boundary explicit.
The Python json module article covers the conversion methods in more detail.
How to Read and Modify a JSON File Step by Step
Open the file as UTF-8 text, decode it once, edit the returned Python value, and save one complete JSON document. This example uses a small settings file, so reading the whole document into memory is a reasonable choice.
Step 1: Prepare the JSON file
Save this content as settings.json beside the Python script. It has a top-level object, a boolean value, a list, and a nested object, which gives the update a few common shapes to work with.
{
"app": "reporter",
"enabled": false,
"tags": ["weekly"],
"limits": {
"retries": 3
}
}
Keep the input valid JSON before loading it. The decoder rejects Python-only syntax such as None or a trailing comma in an object instead of treating the file as Python code. Both Path.open() calls specify UTF-8, so the example does not depend on the operating system’s default text encoding.
The relative path settings.json is resolved from the process’s current working directory. Run the command in the directory containing both files, or build an absolute path from the script location when a scheduler may start it elsewhere.
Step 2: Change values in the decoded object
After json.load() reads this file, settings is a Python dictionary. A direct assignment changes an existing field, and a second key lookup reaches the nested retries value. The tags field is a Python list, so append adds an item and remove deletes a matching item.
The example changes enabled from false to true, raises the retry count, and adds reviewed only when it is not already in the list. That membership check makes another run safe from adding the same tag again.
Changes to settings exist only in memory until the write step succeeds. If validation or a list operation raises an exception first, the original file has not been replaced by this example. Decide whether a repeated update should be idempotent, as the tag addition is here, or whether a second run should create another item.
| Update goal | Python operation | Check |
|---|---|---|
| Change a setting | Assign the dictionary value | Confirm the key is present when required |
| Change a nested setting | Follow each dictionary key | Check the intermediate value has the expected type |
| Add a list item | Append the value | Guard against a duplicate when runs repeat |
| Remove a list item | Remove the selected value | Handle absence and decide whether to remove one or every match |
Nested edits need the right path. If settings contains a list under servers, select an item by its numeric index before using a dictionary key on that item. A missing key raises KeyError when accessed with brackets, while using get() returns a fallback that you can handle deliberately.
Choose a deliberate policy for boolean and numeric settings. A string such as “true” remains text after parsing, and json.load() does not coerce it to the boolean True.
List removal has its own edge case. remove() deletes the first matching value and raises ValueError when the value is absent, so test membership first when absence is expected. For repeated values, filter the list or use a loop that states whether the operation should remove one match or every match.
When a list contains objects, select by a stable identifier rather than a display name. Display names can repeat, so matching a unique ID avoids updating the wrong record.
Step 3: Write a complete replacement and verify it
Writing directly over the original with r+ can leave stale characters if the new JSON is shorter. Seeking to the beginning changes the write position, but it does not shorten the file. I used a named temporary file in the same directory, then replaced the original only after serialization completed.
The temporary file receives its own permissions, so check ownership and mode when another service needs access to the updated settings.
Save the following as json_update_demo.py beside settings.json. It loads the original, updates the dictionary and list, writes readable UTF-8 JSON to a temporary file, replaces settings.json, then loads the result again. The final read checks that the file on disk is valid JSON.
indent=2 adds whitespace for people who inspect the file, and ensure_ascii=False keeps non-ASCII characters readable instead of escaping them. The explicit newline after the serialized object leaves the text file with a conventional final line break. These choices change formatting, not the decoded JSON value.
import json
import os
from pathlib import Path
from tempfile import NamedTemporaryFile
config_path = Path("settings.json")
with config_path.open(encoding="utf-8") as source:
settings = json.load(source)
settings["enabled"] = True
settings["limits"]["retries"] = 5
if "reviewed" not in settings["tags"]:
settings["tags"].append("reviewed")
temporary_path = None
try:
with NamedTemporaryFile(
mode="w",
encoding="utf-8",
dir=config_path.parent,
prefix=f"{config_path.name}.",
suffix=".tmp",
delete=False,
) as temporary:
json.dump(settings, temporary, ensure_ascii=False, indent=2)
temporary.write("\n")
temporary_path = Path(temporary.name)
os.replace(temporary_path, config_path)
finally:
if temporary_path is not None and temporary_path.exists():
temporary_path.unlink()
with config_path.open(encoding="utf-8") as updated_file:
updated_settings = json.load(updated_file)
print(json.dumps(updated_settings, ensure_ascii=False, indent=2))
Step 4: Run the file and check its output
Run the program from the directory containing both files. I ran this exact command with Python 3.14.7 and then read the updated settings.json back with json.load(). The output contains the changed boolean, retry count, and list item.
python3 json_update_demo.py
{
"app": "reporter",
"enabled": true,
"tags": [
"weekly",
"reviewed"
],
"limits": {
"retries": 5
}
}
The saved file contains one updated JSON object, and the program successfully decodes it after replacement. I chose indent=2 for a compact layout that still shows the nested object and array clearly. The pretty-print JSON tutorial explains the same formatting option for output you only need to inspect.
JSON File Modification Errors and Limits
I checked the official json documentation for the parser error and input-size warnings in this table. Failures can happen before the update or while the changed value is being serialized. Check the exception and decoded type to choose a repair, and do not hide an invalid or incomplete configuration behind a fallback value.
| Case | What you see | What to check |
|---|---|---|
| Wrong path | FileNotFoundError | Resolve the path from the script’s working directory or use an explicit Path. |
| Invalid or partly written JSON | JSONDecodeError | Check the reported line and column, quotes, commas, and whether another process wrote the file. |
| Key or container mismatch | KeyError or TypeError | Inspect the decoded type and confirm each key or list index exists. |
| Value Python cannot encode | TypeError during json.dump() | Convert the value to a JSON-supported type or define a deliberate encoder. |
| Large single document | High memory use or long parse time | json.load() decodes a complete document, so use a streaming parser or record-oriented format when the data design allows it. |
JSON has no comment syntax, so a line beginning with a hash mark produces a decoder error. Put explanations in a separate README or use a format designed to permit comments. To investigate JSONDecodeError, inspect its line and column and compare that location with the file’s quotes and separators.
A standard JSON document has one top-level value, so repeated dumps produce adjacent text rather than one parseable document. JSON Lines is a separate convention with one independently parseable value on each line.
A process can save a valid result based on stale data, silently undoing a change another process made seconds earlier. Coordinate writers with a lock or move the data to storage that provides transactions and conflict handling.
For untrusted input, set a maximum file size before parsing. Python’s documentation warns that hostile JSON can consume considerable CPU and memory. For a large document, json.load() still materializes the complete value, so a streaming parser may fit better if the data shape supports incremental processing.
Serialization can also fail after loading succeeds. The standard encoder supports basic JSON values, but a datetime, Path, or custom class needs an explicit conversion rule. A generic string conversion may change the data model when later code needs the original type.
Conclusion: Save the Parsed Python Value
Python edits the value created from JSON, then serializes that value back to a file. Use the file methods for disk data, check the result after saving, and validate the expected structure before your application relies on it.
For method details, use the Python json documentation, including its notes on file objects and JSONDecodeError. The related Python json module and pretty-print JSON articles cover conversion and formatting.
FAQ
For a small complete document, I use the standard library json module and verify the output by loading the saved file again.
What is the difference between json.load() and json.loads()?
json.load() reads JSON from an open file object. json.loads() parses JSON text that is already in a string.
How do I add or remove an item in a JSON list?
Load the file with json.load(), update the resulting Python list with append() or remove(), then save the complete value with json.dump().
Does json.dump() replace the whole file?
json.dump() writes at the file object’s current position and does not truncate it. Write to a fresh temporary file and replace the original, or explicitly truncate when using an in-place strategy.

