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.

Medium Python 3.9+ Aug 9, 2026 Files & data 17 views 0 copies

Python code

33 lines
Python 3.9+
import 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

stdout
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

  1. Use `tempfile.NamedTemporaryFile` with `delete=False` and then os.replace, but that doesn't give you a file descriptor to fsync.
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Files & data

Related tutorials and quizzes for this topic.