Open-Source Wikis

/

Bun

/

Systems

/

Watcher & hot reload

oven-sh/bun

Watcher & hot reload

src/Watcher.zig (~27 KB) is the cross-platform file-system watcher. It is the bottom of two stacks: bun --watch / bun --hot for the runtime, and the dev server (Bake) for HMR.

What the watcher does

  • Subscribes to FS notifications: inotify (Linux), FSEvents (macOS), ReadDirectoryChangesW (Windows).
  • Maintains a deduplicated set of watched paths; one entry per parent directory plus interest in matching children.
  • Coalesces bursts of changes (e.g. an editor writing to a temp file then renaming) before notifying subscribers.
  • Posts events via ConcurrentTask to subscribers' event loops.

The watcher runs on its own OS thread and translates platform-specific events into a uniform WatchEvent enum. See src/watcher/ for platform helpers.

The runtime hot-reload path

src/bun.js/hot_reloader.zig (~28 KB) is the runtime side. It:

  1. Subscribes the watcher to every file the module loader touches.
  2. On a change, invalidates entries in RuntimeTranspilerCache and the module loader's resolved-path cache.
  3. For --watch: tears down the VM and re-runs the entry script.
  4. For --hot: replaces the changed module's record in the JSC module loader and re-runs side effects up to the closest module that doesn't define export default $hot.accept(...).

--hot is best-effort: if the changed module is part of a non-pure dependency chain, behaviour is up to user code.

The dev-server (Bake) hot-reload path

Bake (src/bake/) builds its own HMR runtime on top of the watcher. The browser side (src/bake/client/hmr-*.ts) wraps every module in an HMRModule that exposes accept() boundaries. When a change arrives:

  1. Watcher notifies DevServer.zig.
  2. The dev server reparses the changed file (only that file).
  3. The bundler diffs the import edges.
  4. A binary patch is sent over WebSocket.
  5. The browser evaluates new module bodies and re-renders if the React tree changed.

See Bake for the rendering side.

Public test seam

Bun.FileSystemRouter, bun --watch, bun --hot, and the Bake dev server all reuse the same watcher. Tests can reach into the watcher via src/cli/test/Scanner.zig to detect file changes in bun test --watch.

Reliability notes

  • macOS FSEvents has higher latency than inotify; the watcher uses kqueue as a fallback in some scenarios.
  • Windows file locking can hold a deletion event back until a sibling closes the file. The watcher treats RENAME + CREATE pairs near in time as one event.
  • Symlinks: by default the watcher watches the symlink target's parent, not the link, so changes to the target are detected.

Integration points

  • Module loaderbun.js/hot_reloader.zig invalidates module records.
  • Dev serversrc/bake/DevServer.zig consumes events and produces HMR patches.
  • Test runnerbun test --watch re-runs only affected files.
  • Resolversrc/resolver/ cache lines are dropped on relevant changes.

Entry points for modification

  • To add a platform backend, edit src/Watcher.zig and add the platform-specific helper under src/watcher/.
  • To change debounce / coalesce behaviour, edit the queue in Watcher.zig.
  • To change --hot semantics, edit hot_reloader.zig.

Key source files

File Purpose
src/Watcher.zig Cross-platform watcher.
src/bun.js/hot_reloader.zig Runtime HMR.
src/bake/DevServer.zig Dev-server HMR.
src/bake/client/hmr-runtime-client.ts Browser HMR client.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Watcher & hot reload – Bun wiki | Factory