Skip to content

watchfiles

watchfiles is a file-watching library and CLI for Python. It uses Rust’s notify crate for filesystem event notifications and exposes both synchronous and asynchronous Python APIs. It is the file watcher behind uvicorn’s --reload mode (bundled in uvicorn[standard]).

Note

watchfiles 1.2.0 is the current stable release, licensed MIT. Requires Python 3.10+. Install with uv add --dev watchfiles or pip install watchfiles. Pre-built wheels are available for Linux (x86_64, aarch64, armv7l, musl), macOS (x86_64, aarch64), and Windows (x86_64, aarch64, i686). Building from source requires a Rust toolchain.

Key Features

  • Filesystem monitoring backed by OS-native APIs (inotify on Linux, FSEvents on macOS, ReadDirectoryChanges on Windows) via the Rust notify crate, with automatic polling fallback
  • Change batching and debouncing handled at the Rust level before events reach Python
  • Synchronous API (watch, run_process) and async API (awatch, arun_process) with anyio support
  • Built-in filters: DefaultFilter (ignores common noise like .git, __pycache__, .pyc), PythonFilter (.py files only), or custom filter functions
  • Standalone CLI for re-running any shell command on file changes
  • Formerly named watchgod; a migration guide covers the rename

CLI

The CLI watches one or more paths and re-runs a command whenever a file changes:

watchfiles "python main.py" src

Common flags:

Flag Purpose
--filter python Only trigger on .py file changes
--filter all Trigger on all file changes (no filtering)
--ignore-paths dir1,dir2 Skip changes in specific directories
--non-recursive Watch only the top-level directory, not subdirectories
--sigint-timeout N Seconds to wait after SIGINT before sending SIGKILL
--grace-period N Seconds after process start before watching for changes
--verbose Set log level to debug

The --target-type flag accepts command, function, or auto (the default). When set to function, the target is a dotted Python path (e.g., mypackage.main.run) executed in-process rather than as a subprocess.

Python API

The sync watch function yields sets of (Change, path) tuples as files are modified:

from watchfiles import watch, Change

for changes in watch("src"):
    for change_type, path in changes:
        print(change_type, path)  # Change.modified, "src/main.py"

run_process combines watching with subprocess management:

from watchfiles import run_process

run_process("src", target="python main.py")

Both have async equivalents (awatch, arun_process) that work with asyncio and anyio.

Pros

  • Fast: Rust-level event handling and debouncing avoids the overhead of polling in Python
  • Pre-built wheels for all major platforms; no compilation needed for most users
  • Async-native with both asyncio and anyio support
  • Ships with sensible default filters that ignore .git, __pycache__, and other noise
  • Battle-tested as uvicorn’s reload backend

Cons

  • Building from source requires a Rust toolchain, which adds friction in environments without pre-built wheels
  • Narrower API than watchdog (no granular event types, no custom event handler classes)
  • Python 3.10+ only; projects supporting older Python versions need an alternative

Learn More

Last updated on