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
ConcurrentTaskto 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:
- Subscribes the watcher to every file the module loader touches.
- On a change, invalidates entries in
RuntimeTranspilerCacheand the module loader's resolved-path cache. - For
--watch: tears down the VM and re-runs the entry script. - 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 defineexport 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:
- Watcher notifies
DevServer.zig. - The dev server reparses the changed file (only that file).
- The bundler diffs the import edges.
- A binary patch is sent over WebSocket.
- 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+CREATEpairs 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 loader —
bun.js/hot_reloader.ziginvalidates module records. - Dev server —
src/bake/DevServer.zigconsumes events and produces HMR patches. - Test runner —
bun test --watchre-runs only affected files. - Resolver —
src/resolver/cache lines are dropped on relevant changes.
Entry points for modification
- To add a platform backend, edit
src/Watcher.zigand add the platform-specific helper undersrc/watcher/. - To change debounce / coalesce behaviour, edit the queue in
Watcher.zig. - To change
--hotsemantics, edithot_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.