> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/zhcndoc/bun/llms.txt
> Use this file to discover all available pages before exploring further.

# Watch Mode

> Auto-reload and hot module reloading in Bun

Bun includes a built-in file watcher that automatically restarts your application when files change, with support for hot module reloading for supported frameworks.

## Quick Start

Run with watch mode:

```bash Watch mode theme={null}
bun --watch run app.ts
```

Any changes to imported files trigger an automatic restart.

## Watch Mode Features

<CardGroup cols={2}>
  <Card title="Auto Restart" icon="rotate">
    Automatically restarts on file changes
  </Card>

  <Card title="Fast Reloads" icon="bolt">
    Optimized for sub-100ms restart times
  </Card>

  <Card title="Smart Detection" icon="brain">
    Only watches imported files, not entire project
  </Card>

  <Card title="Cross-Platform" icon="globe">
    Works on macOS, Linux, and Windows
  </Card>
</CardGroup>

## Basic Usage

### CLI Flag

```bash Watch flag theme={null}
# Run script with watch
bun --watch run server.ts

# Run file directly
bun --watch server.ts

# With arguments
bun --watch run app.ts --port=3000
```

### Watch Patterns

```bash Watch specific patterns theme={null}
# Watch TypeScript files only
bun --watch "src/**/*.ts" run app.ts

# Multiple patterns
bun --watch "src/**/*.{ts,tsx}" run app.ts
```

## Hot Module Reloading

For React and other frameworks, use `--hot` for hot module reloading:

```bash Hot reload theme={null}
bun --hot run app.tsx
```

**Hot reload features:**

* Preserves application state
* Updates modules without full restart
* React Fast Refresh support
* Framework-agnostic HMR API

Implementation: `src/runtime.zig:149` - Hot module reloading flag

## Watch Mode Implementation

Bun's watcher uses platform-specific APIs:

### macOS (kqueue)

```zig Watcher platform (src/Watcher.zig:143-148) theme={null}
const Platform = switch (Environment.os) {
    .linux => @import("./watcher/INotifyWatcher.zig"),
    .mac => @import("./watcher/KEventWatcher.zig"),
    .windows => WindowsWatcher,
    .wasm => @compileError("Unsupported platform"),
};
```

**kqueue features:**

* File descriptor-based watching
* Low latency notifications
* Directory monitoring

Implementation: `src/watcher/KEventWatcher.zig`

### Linux (inotify)

**inotify features:**

* Kernel-level file monitoring
* Efficient event batching
* Recursive directory watching

Implementation: `src/watcher/INotifyWatcher.zig`

### Windows

**ReadDirectoryChangesW features:**

* Native Windows file watching
* Buffer-based event delivery
* Directory tree monitoring

Implementation: `src/watcher/WindowsWatcher.zig`

## Watch Events

Watch events are tracked and delivered:

```zig Watch events (src/Watcher.zig:1-49) theme={null}
pub const Watcher = struct {
    watch_events: []WatchEvent = &.{},
    changed_filepaths: [max_count]?[:0]u8,
    
    platform: Platform,
    watchlist: WatchList,
    watched_count: usize,
    mutex: Mutex,
    
    ctx: *anyopaque,
    onFileUpdate: *const fn (this: *anyopaque, events: []WatchEvent, changed_files: []?[:0]u8, watchlist: WatchList) void,
    onError: *const fn (this: *anyopaque, err: bun.sys.Error) void,
};
```

**Event types:**

* File modified
* File created
* File deleted
* File renamed

## Configuration

### Watch Ignore Patterns

Ignore specific files/directories:

```bash Ignore patterns theme={null}
# Ignore node_modules
bun --watch --ignore "node_modules/**" run app.ts

# Multiple ignore patterns
bun --watch \
  --ignore "node_modules/**" \
  --ignore "dist/**" \
  --ignore "*.test.ts" \
  run app.ts
```

### Watch Include Patterns

Only watch specific files:

```bash Include patterns theme={null}
# Only watch src directory
bun --watch "src/**/*.ts" run app.ts
```

## Programmatic Watcher

Create a watcher programmatically:

```typescript Programmatic watcher theme={null}
import { watch } from "fs";

const watcher = watch("./src", { recursive: true }, (eventType, filename) => {
  console.log(`${eventType}: ${filename}`);
});

// Stop watching
watcher.close();
```

### Custom Watcher

Integrate Bun's watcher:

```typescript Custom watcher integration theme={null}
import type { Watcher } from "bun";

class MyWatcher {
  static onFileUpdate(
    events: Watcher.Event[],
    changedFiles: string[],
    watchlist: Watcher.ItemList,
  ) {
    console.log("Files changed:", changedFiles);
    
    // Custom reload logic
    for (const file of changedFiles) {
      console.log(`Reloading ${file}`);
    }
  }
}
```

## React Fast Refresh

Enable React Fast Refresh for hot reloading:

```bash React Fast Refresh theme={null}
bun --hot run app.tsx
```

**Features:**

* Preserves component state
* Updates on save
* Error overlay
* Automatic boundary detection

```tsx React Fast Refresh example theme={null}
import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

// Edit this component - state is preserved!
```

Implementation: `src/runtime.zig:145-147` - React Fast Refresh feature

## Performance

### Debouncing

Bun debounces file changes to avoid excessive reloads:

* **Default debounce**: 50ms
* **Batches multiple changes**: Single reload for rapid file saves
* **Smart filtering**: Ignores non-imported files

### Optimization Tips

1. **Ignore large directories**
   ```bash theme={null}
   bun --watch --ignore "node_modules/**" run app.ts
   ```

2. **Watch specific patterns**
   ```bash theme={null}
   bun --watch "src/**/*.{ts,tsx}" run app.ts
   ```

3. **Minimize file I/O in watch callbacks**

## Development Workflows

### Backend Server

```bash Backend watch theme={null}
bun --watch run server.ts
```

```typescript Express server theme={null}
import express from "express";

const app = express();

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});
```

Edit routes → automatic server restart.

### Frontend Development

```bash Frontend watch theme={null}
bun --hot run dev.tsx
```

```tsx React app theme={null}
import { createRoot } from "react-dom/client";
import App from "./App";

const root = createRoot(document.getElementById("root")!);
root.render(<App />);
```

Edit components → hot module reload.

### Tests

```bash Test watch theme={null}
bun --watch test
```

Runs tests on file changes.

## Watcher Trace

Debug watcher events:

```bash Watcher trace theme={null}
BUN_WATCHER_TRACE=1 bun --watch run app.ts
```

Outputs:

* Files being watched
* Change events
* Reload triggers

Implementation: `src/Watcher.zig:98-108` - Trace initialization

## Error Handling

### Watcher Errors

Handle watcher initialization errors:

```typescript Error handling theme={null}
try {
  // Start watcher
} catch (err) {
  if (err.code === "ENOSPC") {
    console.error("Too many files to watch. Increase fs.inotify.max_user_watches");
  }
}
```

### Linux: Increase Watch Limit

```bash Increase inotify limit theme={null}
# Temporary
sudo sysctl fs.inotify.max_user_watches=524288

# Permanent
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
```

## Advanced Features

### Custom Watch Callback

```typescript Watch callback theme={null}
import { Watcher } from "bun";

const watcher = new Watcher({
  onUpdate(events) {
    console.log(`${events.length} files changed`);
    // Custom reload logic
  },
  onError(error) {
    console.error("Watcher error:", error);
  },
});
```

### Selective Watching

Only watch specific modules:

```typescript Selective watching theme={null}
import { watch } from "fs";

const watchedModules = new Set(["./src/app.ts", "./src/config.ts"]);

watch("./src", { recursive: true }, (event, filename) => {
  if (watchedModules.has(filename)) {
    console.log(`Watched file changed: ${filename}`);
  }
});
```

## Integration Examples

### Express + Watch

```typescript Express watch theme={null}
import express from "express";

const app = express();
let server: any;

function startServer() {
  server = app.listen(3000, () => {
    console.log("Server started");
  });
}

function stopServer() {
  server?.close();
}

startServer();

// Graceful reload on watch
process.on("SIGTERM", () => {
  stopServer();
});
```

### Next.js-like Dev Server

```typescript Dev server theme={null}
import { watch } from "fs";
import { build } from "bun";

async function buildAndServe() {
  await build({
    entrypoints: ["./src/index.tsx"],
    outdir: "./dist",
  });
  
  Bun.serve({
    port: 3000,
    fetch: () => new Response(Bun.file("./dist/index.html")),
  });
}

await buildAndServe();

watch("./src", { recursive: true }, async () => {
  console.log("Rebuilding...");
  await buildAndServe();
});
```

## Troubleshooting

### Watch Not Detecting Changes

1. **Check file is imported**: Watcher only tracks imported files
2. **Check ignore patterns**: File might be ignored
3. **Check watch limit (Linux)**: Increase `fs.inotify.max_user_watches`

### High CPU Usage

1. **Ignore large directories**: `--ignore "node_modules/**"`
2. **Reduce watch scope**: `--watch "src/**/*.ts"`
3. **Increase debounce**: Custom watcher with longer debounce

### Slow Reloads

1. **Reduce imports**: Minimize dependency graph
2. **Use hot reload**: `--hot` instead of `--watch`
3. **Profile startup**: Measure import time

## Related

* [Hot Module Reloading](/runtime/hot-reload) - HMR API documentation
* [Debugger](/runtime/debugger) - Debugging with watch mode
* [React Fast Refresh](https://react.dev/learn/fast-refresh) - React HMR
