How to Use Watchexec: The Beginner's Guide (First Watch, the Extension-Filter Lesson, First Restart, and the Ignore-File Payoff)

CodexFuse Team · 2026-11-02T09:02:26.580Z · 14 min read min read

Learn how to use watchexec: install it in one command, run your first watch, filter by extension, auto-restart your dev server, and let .gitignore do the ignoring.

How to Use Watchexec: The Beginner's Guide (First Watch, the Extension-Filter Lesson, First Restart, and the Ignore-File Payoff)

Learning how to use watchexec starts with one mental model, said once: watchexec = run this command whenever files change. The README's exact line is "watchexec is a simple, standalone tool that watches a path and runs a command whenever it detects modifications" — a single Rust binary, created by Félix Saparelli in 2016, that turns any command you type into one that re-runs itself. This watchexec tutorial walks the full beginner arc: install, your first watch, the extension-filter lesson, your first restart, and the ignore-file payoff — with every command verified against watchexec 2.8.0 on November 2, 2026, including two behaviors I tested live on this run. If you searched "how to use watchexec" and found only man pages and install aggregators, this page is the missing unified beginner guide. It pairs naturally with the canonical first demo command, watchexec make — our Make beginner guide covers the build tool half of that pairing.

Who is it for? Any developer who re-runs a build, test suite, or dev server by hand after every save. You need a terminal, a project directory, and a command that already works when you type it manually. Nothing else is required — the README's three canonical use cases are "Automatically run unit tests", "Run linters/syntax checkers", and "Rebuild artifacts".

What Is Watchexec, Exactly?

Watchexec is a file watcher for the command line: you give it a command, and it re-runs that command every time a watched file changes. In one sentence: watchexec exists to auto run command on file change — that is the whole product, and every flag below serves that one job. It is written in Rust, ships as one standalone binary, is licensed Apache-2.0, and the GitHub repo describes it as "Executes commands in response to file modifications". Snapshot on November 2, 2026: created 2016-09-18, roughly 7,267 stars and 211 forks (those numbers move daily). Under the hood it "recursively monitors the current directory for changes, executing the command when a filesystem change is detected", using efficient kernel-level mechanisms by default, per the built-in help.

Your first watch in five steps:

  1. Install watchexec (next section — one command on every major OS).
  2. Change into a project directory that has something to build or run.
  3. Type watchexec make and press Enter.
  4. Save any source file in the project.
  5. Watch watchexec run your command again, automatically.

One behavior to know before step 3: "At startup, the specified command is run once, and watchexec begins monitoring for changes." That first run is intentional — it confirms your command works — and if you would rather wait for the first file change, add --postpone: "Wait until first change before running command".

How Do You Install Watchexec on Linux, macOS, and Windows?

The answer is one command from your package manager — or cargo install watchexec-cli if you have the Rust toolchain (said once; the docs suggest the locked variant, cargo install --locked watchexec-cli). Current version at write time is 2.8.0 (published October 6, 2026, per the GitHub releases API fetched this run).

PlatformMethodCommand
macOSHomebrewbrew install watchexec
Debian / UbuntuAPTapt install watchexec
Arch Linuxpacmanpacman -S watchexec
Alpineapkapk add watchexec
Nixnix-shellnix-shell -p watchexec
WindowsChocolatey or Scoopchoco install watchexec or scoop install watchexec
Any (Rust users)cargo-binstallcargo binstall watchexec-cli
Any (from source)cargocargo install --locked watchexec-cli

Prebuilt DEB, RPM, and tar.xz archives are also published on the GitHub releases page for every version. If you searched "file watcher linux" hoping for a one-command install, this is it: apt, pacman, and apk all ship watchexec natively. I installed the official 2.8.0 x86_64 Linux tarball on this run and every behavior below was verified against that exact binary. Confirm your install with watchexec --version, which should report 2.8.0.

Your First Watch: watchexec make

The classic first demo is literally watchexec make: it runs make once at startup, then re-runs it every time any file under the current directory changes. The README lists it first among its demos for a reason — if your project has a Makefile, this is the entire getting-started story. By default "Watchexec watches the current directory", recursively; scope it with -w ("Watch a specific file or directory", repeatable), -W for a non-recursive directory watch, or -F for a single file.

The README's classic watchexec examples, all verbatim and all current:

CommandWhat it does
watchexec makeRebuild the project on any change
watchexec -c make testRe-run tests, clearing the screen each time
watchexec -e js,css,html npm run buildRebuild the frontend only when web files change
watchexec -w lib -w src makeWatch only lib and src, rebuilding each time
watchexec -r node app.jsRun a dev server and restart it on changes
watchexec -N go buildRebuild Go code, with a desktop notification each run

A real run looks like this — note the markers watchexec prints around your command's own output:

$ watchexec -c make test
[Running: make test]
ok  14 passed
[Command was successful]

Flags that belong to your command should be separated with -- (for example, watchexec -w src -- rsync -a src dest), though the help notes it is not strictly required. And take care with globs: the help warns that your shell may expand them before watchexec ever sees them — watchexec echo src/*.rs and watchexec echo 'src/*.rs' are different commands.

The Extension-Filter Lesson: Why -e Is the Flag Beginners Learn First

Watching everything is the beginner mistake, said once. Without a filter, every save re-runs your command — including notes files, screenshots, and editor temp files. The whole watchexec extensions story is this one flag, -e / --exts: "Filename extensions to filter to. This is a quick filter to only emit events for files with the given extensions. Extensions can be given with or without the leading dot (e.g. 'js' or '.js'). Multiple extensions can be given by repeating the option or by separating them with commas." I verified this live on watchexec 2.8.0: I ran watchexec --postpone -e txt -- echo REBUILT, touched a .md file (nothing happened), then touched a .txt file — and the command fired exactly once, printing REBUILT. The filter is real, and it is the difference between a watcher that feels magic and one that feels broken.

The three filtering tools, and when to reach for each:

FlagMeaningUse it when
-e / --exts"Filename extensions to filter to"You only care about certain file types (-e rs,toml)
-f / --filter"Filename patterns to filter to"You need glob patterns beyond extensions
-i / --ignore"Filename patterns to filter out"You want everything except some patterns

Caution, said once: -E is not an ignore-events flag — it is --env, "Add env vars to the command" (KEY=VALUE, repeatable). The event-kind filter is --fs-events, which by default includes everything except access events.

Your First Restart: -r and the Dev-Server Payoff

This is the dev-server killer feature, one section: -r / --restart means "Restart the process if it's still running", and it is "a shorthand for '--on-busy-update=restart'". The demo is watchexec -r node app.js — your server starts, you edit code, save, and watchexec kills the old process and boots a fresh one. Without -r, a change that arrives while the command is still running waits its turn; with -r, the stale process is terminated and the command restarts with your new code.

The README's canonical restart demos: watchexec -r node app.js and watchexec -r -e py -- python server.py (restart only when Python files change — the extension-filter lesson and the restart lesson compose). The stop signal used for the graceful shutdown is controlled by --stop-signal, which defaults to SIGTERM on Unix; combine with --postpone so the server only boots after your first change. Related polish: --timeout ("Kill the command if it runs longer than this duration") keeps hung processes from lingering, and --exit-on-error ("Exit when the command has an error") makes watchexec play nicely inside containers and process managers.

The Ignore-File Payoff: .gitignore Is Respected Automatically

The ignore-file payoff, said once: by default, watchexec "uses .gitignore, .ignore, and other such files to determine which files to ignore notifications for" — no flag required. Most watchexec ignore questions resolve the same way: the ignores are already loaded, so your only real decision is when to opt out of them. That single behavior deletes an entire class of beginner annoyance: node_modules, build output, and log files never trigger a rebuild, because git already told watchexec to skip them. The man page inventories exactly what is loaded: Git's .gitignore at the project root and in child directories, .git/info/exclude, and the file pointed to by core.excludesFile, plus Mercurial's .hgignore, Bazaar's .bzrignore, Darcs' _darcs/prefs/boring, Fossil's .fossil-settings/ignore-glob, and generic .ignore files — VCS files only count when that VCS is actually in use.

I proved this live: with a .gitignore containing ignored.txt, I ran watchexec --postpone -e txt -- echo FIRED — touching ignored.txt fired nothing, and touching real.txt fired exactly once. If the ignore behavior ever surprises you, the man page is explicit about the cause and the cure: "This option is useful if you want to watch files that are ignored by Git" — the option being --no-vcs-ignore, with siblings --no-project-ignore, --no-global-ignore, and the blanket --ignore-nothing. If git's ignore rules are new to you, our Git beginner guide covers them from the ground up. One migration note for v1 users, said once: the old --no-process-group flag is deprecated — use --wrap-process=none instead.

The Polish Pass: Notifications, Clear Screen, and Quiet Mode

Once the loop works, add the polish in one pass: -N / --notify ("Alert when commands start and end") pops a desktop notification when each run starts and ends, with modes start, end, or both (the default); -c / --clear ("Clear screen before running command") wipes the terminal before each run so the latest output is all you see (try --clear=reset if a plain clear leaves artifacts); and -q / --quiet ("Don't print starting and stopping messages") silences watchexec's own chatter. A long watch session on a slow machine can pair -q with -N: no terminal noise, but a toast tells you the run finished.

One more flag deserves a paragraph: -d / --debounce, "Time to wait for new events before taking action". "The default is 50 milliseconds. Setting to 0 is highly discouraged." A single save can emit a burst of filesystem events, and some editors write files non-atomically — debounce collapses the burst so your command runs once, on a settled file, instead of three times on a half-written one. Locally you run the fast loop; the full suite still belongs in CI — our GitHub Actions beginner guide covers the other half of that split. And for scripting, --only-emit-events turns watchexec into a pure event stream ("Only emit events to stdout, run no commands"), emitting JSON by default.

Watchexec vs Entr: Which File Watcher Should You Pick?

Pick watchexec if you want zero plumbing. The classic alternative, entr, needs its file list piped in — the familiar find src -name '*.rs' | entr cargo test idiom — while watchexec watches the directory itself, no pipe required. The README states this as an explicit anti-feature: watchexec "does not require a cryptic command line involving xargs". For a file watcher on Linux, macOS, or Windows, the comparison below is the honest one:

watchexecentrnodemon / chokidar-cli
Watching modelWatches directories itselfReads file list from stdinWatches directories itself
Runtime neededNone — single Rust binaryNone — tiny C binaryNode.js
Command environmentRuns the command in a shell by defaultRuns via shell / sh -cNode process
Ignore files.gitignore / .ignore automaticManual (you pipe what you want)Varies by tool
Restart mode-r built in-r built inBuilt in
Best forAny language, zero setupMinimalists who like pipesNode.js projects already in the ecosystem

If you come from entr, one note from the docs.rs CLI README: "If you come from entr, note that the watchexec command is run in a shell by default. You can use -n or --shell=none to not do that" — -n is "Shorthand for '--shell=none'". Sibling line, said once: entr, nodemon, and chokidar-cli are not rivals to this guide — they are the comparison set for the same intent, and this page covers the cluster's comparison keyword here rather than on a separate page.

7 Beginner Mistakes That Make Watchexec Feel Broken

Every one of these comes from the docs or from live testing on this run — the fix column is the one-line cure.

#MistakeWhat happensFix
1Watching everything (no filter)Every stray save re-runs the command-e rs,toml — filter to the extensions you care about
2Surprised the command ran immediately"At startup, the specified command is run once" — by design--postpone to wait for the first change
3Editing an ignored file, expecting a trigger.gitignored files never fire--no-vcs-ignore if you truly want ignored files watched
4Using -E to "ignore events"You set an env var instead-E is --env; use -i or --fs-events
5Expecting $WATCHEXEC_UPDATED_PATH (v1 habit)The variable no longer exists in v2Event emission is opt-in via --emit-events-to
6Hunting for a config fileThere is no .watchexec.tomlUse @argfile and env vars like $WATCHEXEC_FILTER_FILES
7Dev server not restarting on saveThe old process keeps running; the new run waits-r — restart the process if it is still running

Where Watchexec Fits: Fast Local Loops, CI Still Runs the Suite

Watchexec owns the inner loop; CI owns the full suite. The README's three use cases — "Automatically run unit tests", "Run linters/syntax checkers", "Rebuild artifacts" — are all local-loop work: the tight feedback you want while editing, before you push. It is the FILE-WATCHER lane opener in this site's dev-workflow cluster, and its pillar is the build tool it pairs with most naturally — our Make beginner guide, because watchexec make is the canonical first demo. The broader lane rule: one page per intent cluster — the comparison, extension, restart, ignore, and examples keywords all live on this one page, never split across rivals.

Sources

  1. watchexec GitHub README (github.com/watchexec/watchexec) — verbatim definition, use cases, demo commands, and the no-xargs anti-feature
  2. docs.rs — watchexec-cli 2.8.0 — install methods, classic demo commands, the "command is run in a shell by default" entr note
  3. Arch Linux man page — watchexec 2.8.0 — verbatim flag descriptions (-e, -r, -w, -N, -c, -q, -d, -p), the 50-millisecond debounce default, the full ignore-file inventory, and the deprecated --no-process-group flag
  4. GitHub releases API (api.github.com/repos/watchexec/watchexec) — v2.8.0 published 2026-10-06, fetched November 2, 2026
  5. watchexec GitHub repo page — created 2016-09-18, Apache-2.0 license, roughly 7,267 stars and 211 forks (snapshot November 2, 2026; moves daily)
  6. watchexec man-page AUTHORS section — Félix Saparelli and Matt Green
  7. Author's own live verification on this run — watchexec 2.8.0 installed from the official GitHub release tarball on this machine; the -e extension-filter test (.md touch ignored, .txt touch fired exactly once) and the .gitignore test (ignored.txt touch fired nothing, real.txt touch fired once)

Frequently Asked Questions

Does watchexec run my command when it starts?

Yes. "At startup, the specified command is run once, and watchexec begins monitoring for changes." That first run confirms your command works before any file changes. Add --postpone ("Wait until first change before running command") if you would rather the first run waits for a real change.

Which files does watchexec watch by default?

The current directory, recursively — minus anything your ignore files exclude. Narrow it with -e (extensions), -w (specific paths, repeatable), -W (non-recursive directory), or -F (single file). On Linux, macOS, and Windows alike, the default is "watch everything here, respect the ignores".

Is there a watchexec config file?

No — there is no .watchexec.toml. For long or repeated invocations, use @argfile (one argument per line in a file) or the documented environment variables such as $WATCHEXEC_FILTER_FILES and $WATCHEXEC_IGNORE_FILES.

How do I make watchexec restart my dev server on every save?

Use -r: watchexec -r node app.js. It means "Restart the process if it's still running", so the stale server is shut down (SIGTERM on Unix by default) and a fresh one boots with your latest code on every save.

Can I use watchexec in CI or scripts without the chatter?

Yes: -q silences the start/stop messages, --exit-on-error exits when the command fails (container- and process-manager-friendly), and --timeout kills runs that hang past a duration you set. For pipelines that consume events directly, --only-emit-events emits a JSON event stream and runs no command at all.

Featured on Twelve Tools Launch Llama Tools Launch your MCP