5.9.5 Filesystem Watching
extra--watchfs changes how a long-lived Bazel server discovers local filesystem
changes between commands. Instead of beginning each incremental command with an
unknown diff, Bazel can ask the operating system for changed paths and use that
short list to invalidate relevant filesystem nodes. This is a startup
optimization. It does not replace Skyframe dependencies, action input checking,
or sandboxing.1,2
Notifications narrow the diff
Without usable change notifications, Bazel's bottom-up invalidation must check
the filesystem state retained from earlier evaluation to discover which inputs
changed. The Skyframe documentation describes this as stat()-ing the input
files of the previous build. In the implementation, the conservative signal is
EVERYTHING_MODIFIED: the diff is unknown, so Bazel must not trust a small set
of paths.1,2
With --watchfs, a watcher reports paths created, modified, or deleted since
the preceding view. Bazel feeds that candidate set into its filesystem-diff
processing, which updates filesystem SkyValues and starts the bottom-up
invalidation described in 5.9.4 Incrementality Mechanism. The notification
does not itself mean that every dependent action executes. Normal
re-evaluation, change pruning, and action-cache checks still apply.1,2
This distinction avoids two misleading summaries:
- Bazel is not merely watching each declared action input. In Bazel 9, local diff awareness is created per package-path entry. The Linux/Java watcher recursively registers directories below that root, excluding configured ignored subtrees and not following symlinked directory trees.2
- The no-watcher path is not accurately described as walking every file that happens to exist in the workspace. It conservatively checks retained filesystem knowledge relevant to the prior graph. The exact work depends on the graph and filesystem-value types Bazel has retained.1,2
Platform scope in Bazel 9
--watchfs is a command option and defaults to false. On Linux, Bazel 9 uses
Java's WatchService, whose Linux implementation uses inotify. On macOS, Bazel
selects its JNI-backed FSEvents implementation rather than Java
WatchService.2,3
Windows is a separate, experimental case: --watchfs alone is a no-op there.
It must be combined with --experimental_windows_watchfs, after which Bazel
uses the Java watcher path. The command reference also leaves behavior
undefined when a workspace is on a network filesystem and files are edited on
another machine. Do not enable the flag as a universal shared .bazelrc
performance rule without checking hosts and workspace storage.3
# A local Linux/macOS profile, enabled deliberately.
build:local_watch --watchfs
The benefit is workload-dependent. It is most plausible when the same server retains a large graph, only a few local paths change, and another command follows. A first command, a restarted server, or a watcher that cannot provide a precise delta still needs conservative checking.2
Uncertain events fail safe
Filesystem notification APIs can say that their event history is incomplete. Bazel 9 handles that uncertainty conservatively rather than treating the reported subset as complete:
- A Java watcher overflow, an event without enough path information, or loss
of the watched root breaks that watcher instance. The diff-awareness manager
reports the problem and supplies
EVERYTHING_MODIFIEDfor that command.2 - The macOS FSEvents polling layer returns an imprecise result when events were
lost. Bazel converts that result to
EVERYTHING_MODIFIED.2 - Enabling watching after a non-watching view, disabling it while active, or comparing incompatible watcher views also forces a conservative boundary rather than reusing a gap in event history.2
“Fallback” therefore means fall back to an unknown/all-modified filesystem diff and verify retained filesystem state. It does not promise one particular literal traversal algorithm on every platform and command. The warning and extra I/O are a correctness safeguard, not evidence that Skyframe's whole in-memory graph was discarded.
--watchfs is an opt-in, between-command diff optimization. Bazel 9 uses
inotify-backed Java watching on Linux and its FSEvents implementation on macOS.
Windows additionally requires an experimental flag. The watcher covers local
package-path roots recursively, not just one watch per declared input.
Notifications nominate changed paths. Skyframe still decides what to invalidate and re-evaluate. When the notification history is missing, overflowed, incompatible, or outside the documented local-filesystem scope, Bazel conservatively treats the diff as all modified instead of risking a stale incremental build.
Check your understanding · 3 questions
1.What does --watchfs optimize between two commands served by the same Bazel server?
Select one answer
2.Assess these Bazel 9 platform and scope claims:
Choose True or False for each sentence
--watchfs alone enables the supported default watcher.3.A filesystem watcher reports an overflow and may have lost changes. What is Bazel's safe response?
Select one answer
Footnotes
-
Skyframe — bottom-up invalidation, retained input checks, and notification-assisted change discovery ↩1 ↩2 ↩3 ↩4
-
Bazel upstream source — Bazel 9.0.0
LocalDiffAwareness, Java WatchService and macOS FSEvents implementations, diff manager, and watchfs integration tests (verified 18 July 2026) ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 -
Command-Line Reference — Bazel 9
--watchfsdefault, Linux/macOS behavior, Windows gate, and network-filesystem caveat ↩1 ↩2