How to Atomically Write Files in Python with Temp File and Rename
Write a file atomically using a temporary file and os.replace so readers never see partial writes even if the process crashes mid-write.
Python code
33 linesimport os
import tempfile
from pathlib import Path
def atomic_write(path: str | Path, content: str) -> None:
"""Write content to path atomically using a temp file and rename."""
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
fd, temp_path = tempfile.mkstemp(
dir=str(path.parent),
prefix=f".{path.name}.",
suffix=".tmp",
text=True
)
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
f.write(content)
f.flush()
os.fsync(f.fileno()) # Ensure data is on disk before rename
os.replace(temp_path, path) # Atomic on POSIX and Windows
except BaseException:
try:
os.unlink(temp_path)
except OSError:
pass
raise
if __name__ == "__main__":
target = Path("data/output.txt")
atomic_write(target, "Hello, atomic world!\n")
print(f"Wrote content to {target}")
print(target.read_text())
Output
Wrote content to data/output.txt
Hello, atomic world!
How it works
The function creates a unique temporary file in the same directory using tempfile.mkstemp, writes the content, flushes the buffer, and forces the data to disk with os.fsync. Then os.replace swaps the temp file into the destination path atomically — on both POSIX and Windows, this is a single rename operation with no chance of a partially written file visible to other processes. If any error occurs before the rename, the temp file is removed in the except block, so the original destination remains untouched. The function also creates the parent directory if needed and supports both str and Path inputs via the type hint.
Common mistakes
- Using os.rename instead of os.replace — os.rename fails on Windows if the destination exists.
- Forgetting to call os.fsync — without it, the OS may not have flushed data to disk before the rename, so a crash can still lose data.
- Not cleaning up the temp file on error — leaving .tmp files behind in the directory.
- Writing the temp file into a different directory — os.replace only works atomically if both files are on the same filesystem.
Variations
- Use `tempfile.NamedTemporaryFile` with `delete=False` and then os.replace, but that doesn't give you a file descriptor to fsync.
- Wrap the logic in a context manager class so you can do `with atomic_open(path) as f:` to write and close atomically.
Real-world use cases
- Persisting application configuration or feature flags where a corrupted file would break startup.
- Writing cache files or data snapshots in data pipelines so readers never see partial or corrupt data.
- Saving user-uploaded files in web services where a crash mid-write shouldn't leave a broken file.
Sponsored
More from Files & data
- Append a Line to a Log File in Python easy
- Audit File Permissions Across a Project in Python easy
- Automatically Detect Corrupted Files Using SHA-256 Checksums in Python easy
- Automatically Highlight Data Validation Errors Inside Excel Files in Python easy
- Build a Command-Line To-Do List Application with Data Persistence in Python easy
- Build a File Index by Relative Path Hash Map in Python easy
Keep learning
Related tutorials and quizzes for this topic.