Modern software development and system administration workflows rely heavily on rapid feedback loops. Manually re-running compiler commands, test suites, linter checks, or development servers every time you modify source code introduces friction and wastes time. While specialized build tools often include proprietary watch modes, they rarely extend cleanly to generic shell scripts, documentation generators, or multi-language projects. Watchexec is an open-source, standalone, cross-platform CLI utility written in Rust that executes arbitrary commands whenever watched files or directories change.
In this guide, you will learn how to install Watchexec on Linux, configure file filtering rules, handle process restarting, pass changed file arguments, and integrate it into your development environment.
What Is Watchexec and How Does It Work?
Watchexec monitors filesystem events using native Linux kernel APIs (such as inotify and fanotify). Unlike simple polling scripts that consume excessive CPU power, Watchexec is event-driven, responding instantly to file modifications, creations, deletions, and attribute changes.
Key highlights of Watchexec include:
- Automatic Debouncing: Coalesces rapid bursts of file modifications (such as editor autosaves or Git checkouts) into a single command invocation, preventing duplicate runs.
- Gitignore Support: Automatically respects project
.gitignoreand.ignorefiles to avoid triggering on temporary build artifacts or dependency directories. - Process Management: Gracefully terminates running processes (via
SIGTERMorSIGKILL) before restarting them upon subsequent file changes. - Environment Variable Injection: Passes lists of modified file paths directly into the child process via environment variables like
$WATCHEXEC_WRITTEN_PATH.
Installing Watchexec on Linux
Watchexec is distributed as a pre-compiled standalone binary and is available across major Linux package managers.
Method 1: Installing via Official Binary (Universal)
To install the latest release directly on Ubuntu, Debian, Fedora, or Rocky Linux:
# Download the latest Watchexec release tarball for 64-bit Linux
curl -sSL https://github.com/watchexec/watchexec/releases/latest/download/watchexec-x86_64-unknown-linux-gnu.tar.xz -o watchexec.tar.xz
# Extract the archive
tar -xf watchexec.tar.xz
# Locate and move the binary into your system path
sudo mv watchexec-*-x86_64-unknown-linux-gnu/watchexec /usr/local/bin/
# Set executable permissions
sudo chmod +x /usr/local/bin/watchexec
# Clean up archive files
rm -rf watchexec.tar.xz watchexec-*-x86_64-unknown-linux-gnu
# Verify installation
watchexec --version
Method 2: Installing via Package Managers
On Arch Linux and Manjaro:
sudo pacman -S watchexec
On systems with Homebrew or Cargo (Rust toolchain):
# Using Homebrew
brew install watchexec
# Using Cargo
cargo install watchexec-cli
Basic Usage and Command Execution
The core syntax of Watchexec separates watcher options from the command you wish to execute:
watchexec [OPTIONS] -- <COMMAND>
Watching the Current Directory
To run a shell script whenever any unignored file in the current project directory changes:
watchexec -- ./scripts/build.sh
Filtering by File Extensions
In most projects, you only want specific source files to trigger rebuilds. Use the -e (or --exts) flag to specify a comma-separated list of extensions:
# Re-run pytest only when Python files change
watchexec -e py -- pytest tests/
# Recompile Go code only on .go file modifications
watchexec -e go -- go test ./...
Advanced Filtering and Ignore Rules
Watching Specific Subdirectories
To restrict filesystem monitoring to a specific folder (such as src/):
watchexec -w src -- cargo check
Ignoring Specific Paths and Glob Patterns
Although Watchexec automatically parses .gitignore, you can add ad-hoc ignore patterns using the -i (or --ignore) flag:
# Ignore SQLite database files and log directories
watchexec -e js,ts -i "*.sqlite" -i "logs/**" -- npm test
If you wish to completely disable default Git ignore parsing and track all files:
watchexec --no-vcs-ignore -- make
Process Management for Long-Running Servers
When developing web services, APIs, or background workers, the process must run continuously until a file change occurs, at which point the old server instance must terminate cleanly before the new instance starts.
Restarting Long-Running Processes
By default, Watchexec waits for a command to finish before executing it again. For servers, use the -r (or --restart) flag to restart the process on change:
# Automatically restart a Node.js server on file changes
watchexec -r -e js,json -- node server.js
# Restart a Python FastAPI/Uvicorn server
watchexec -r -e py -- python -m app.main
Customising the Termination Signal
If your application requires a specific termination signal to flush database pools or commit transactions, specify the signal using -s:
watchexec -r -s SIGQUIT -- ./bin/server
Clearing the Terminal Screen Between Runs
To maintain a clean terminal view and instantly see new test results or compilation warnings, use the -c (or --clear) flag:
watchexec -c -e rs -- cargo test
Watchexec clears the terminal viewport before each command execution, making it immediately apparent when tests succeed or fail.