watchexec

A simple, standalone tool that watches a path and runs a command whenever it detects modifications.

watchexec is a general-purpose file watcher that runs a command whenever files in a directory change. It's the Swiss Army knife of watch-and-run tools — simpler than Makefiles, more flexible than language-specific watchers like cargo-watch, and usable with any command or project type.

Features

  • Language agnostic — works with any command: make, cargo, python, npm run, anything
  • Smart filtering — ignores version control directories, build artefacts, and hidden files by default
  • Debouncing — waits for a burst of changes to settle before triggering, so a bulk save doesn't spawn dozens of runs
  • Signal control — configurable signal sent to the running process before restarting (e.g. SIGTERM, SIGKILL, SIGHUP)
  • Clear screen — optionally clear the terminal between runs for a clean view each time
  • Ignore files — respects .gitignore, .ignore, and custom ignore files
  • On-change environment — injects environment variables describing which files changed so your command can react to them

Installation

cargo install watchexec-cli

Or via your system package manager:

# Debian / Ubuntu (Debian 12+)
apt install watchexec

# Fedora
dnf install watchexec

# macOS
brew install watchexec

# Arch Linux
pacman -S watchexec

# Nix
nix-env -iA nixpkgs.watchexec

Usage

# Rerun a command whenever any file in the current directory changes
watchexec -- make build

# Watch only Rust source files
watchexec --exts rs -- cargo test

# Watch a specific directory
watchexec --watch src -- npm run build

# Clear the terminal before each run
watchexec --clear -- cargo run

# Send SIGHUP to the process instead of killing it (useful for servers that reload on SIGHUP)
watchexec --signal SIGHUP -- ./my-server

# Restart a long-running process (e.g. a dev server) on change
watchexec --restart -- python app.py

# Ignore specific paths
watchexec --ignore target --ignore node_modules -- make

# Only trigger on specific events (create, modify, remove, rename)
watchexec --on-busy-update restart -- cargo check

Environment variables injected on change

When a command runs, watchexec provides details about what triggered it:

VariableDescription
WATCHEXEC_COMMON_PATHLongest common path of all changed files
WATCHEXEC_CREATED_PATHPaths of created files
WATCHEXEC_REMOVED_PATHPaths of removed files
WATCHEXEC_RENAMED_PATHPaths of renamed files
WATCHEXEC_WRITTEN_PATHPaths of modified files

This makes it easy to write scripts that act on the specific file that changed:

watchexec --shell=bash -- 'echo "Changed: $WATCHEXEC_WRITTEN_PATH"'

Comparison with cargo-watch and bacon

watchexec is more general than cargo-watch or bacon — it doesn't know anything about Rust specifically. That's its strength: the same mental model applies whether you're working on a Rust project, a Python script, a LaTeX document, or a shell pipeline. For Rust-specific workflows with formatted compiler output, bacon is more ergonomic; for everything else, watchexec is hard to beat.