> ## 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.

# Workers

> Run JavaScript in parallel threads with Web Workers

Bun implements the Web Workers API for running JavaScript in parallel threads. Workers are useful for CPU-intensive tasks, parallel processing, and isolating code execution.

## Creating a Worker

```ts theme={null}
const worker = new Worker("worker.ts");

worker.postMessage({ task: "compute", data: [1, 2, 3] });

worker.onmessage = (event) => {
  console.log("Result:", event.data);
};
```

In `worker.ts`:

```ts theme={null}
self.onmessage = (event) => {
  const { task, data } = event.data;
  
  if (task === "compute") {
    const result = data.reduce((a, b) => a + b, 0);
    self.postMessage(result);
  }
};
```

## Worker Options

### Module Type

Workers can be ES modules or classic scripts:

```ts theme={null}
// ES Module (default in Bun)
const worker = new Worker("worker.ts", { type: "module" });

// Classic script
const worker = new Worker("worker.js", { type: "classic" });
```

### Worker Name

Name workers for debugging:

```ts theme={null}
const worker = new Worker("worker.ts", { name: "DataProcessor" });

console.log(worker.name); // "DataProcessor"
```

### Credentials

Control credential passing for module imports:

```ts theme={null}
const worker = new Worker("worker.ts", {
  credentials: "same-origin", // or "include", "omit"
});
```

## Communication

### Posting Messages

Send data between main thread and worker:

```ts theme={null}
// Main thread
worker.postMessage({ type: "start", config: { threads: 4 } });

// Worker
self.onmessage = (event) => {
  const { type, config } = event.data;
  // Process message
};
```

### Message Event

```ts theme={null}
worker.addEventListener("message", (event) => {
  console.log("Received:", event.data);
});

// Or using property
worker.onmessage = (event) => {
  console.log("Received:", event.data);
};
```

### Error Handling

```ts theme={null}
worker.addEventListener("error", (event) => {
  console.error("Worker error:", event.message);
  console.error("File:", event.filename);
  console.error("Line:", event.lineno);
});

worker.onerror = (event) => {
  console.error("Error in worker:", event.message);
};
```

### Unhandled Rejections

```ts theme={null}
worker.addEventListener("messageerror", (event) => {
  console.error("Message deserialization failed");
});
```

## Transferring Data

### Structured Clone

By default, data is cloned:

```ts theme={null}
const data = { numbers: [1, 2, 3], text: "hello" };
worker.postMessage(data);
// `data` is cloned and can still be used
```

Supported types:

* Primitives (string, number, boolean)
* Objects and Arrays
* `Date`, `RegExp`, `Map`, `Set`
* `ArrayBuffer`, `TypedArrays`
* `Blob`, `File`, `ImageData`

### Transfer Objects

For better performance, transfer ownership:

```ts theme={null}
const buffer = new ArrayBuffer(1024 * 1024); // 1MB

// Transfer ownership to worker
worker.postMessage({ buffer }, [buffer]);

// buffer is now detached and unusable in main thread
console.log(buffer.byteLength); // 0
```

Transferable types:

* `ArrayBuffer`
* `MessagePort`
* `ReadableStream`
* `WritableStream`
* `TransformStream`

### Shared Memory

Use `SharedArrayBuffer` for shared memory:

```ts theme={null}
// Main thread
const shared = new SharedArrayBuffer(1024);
const view = new Int32Array(shared);

worker.postMessage({ shared });

// Both threads can access the same memory
view[0] = 42;

// Worker thread
self.onmessage = ({ data }) => {
  const view = new Int32Array(data.shared);
  console.log(view[0]); // 42
  view[0] = 100;
};
```

## Worker Lifecycle

### Terminating Workers

```ts theme={null}
// Graceful shutdown
worker.postMessage({ type: "shutdown" });

// Force terminate
worker.terminate();
```

Inside the worker:

```ts theme={null}
self.onmessage = (event) => {
  if (event.data.type === "shutdown") {
    // Cleanup
    self.close(); // Terminate from inside
  }
};
```

### Reference Counting

Control whether worker keeps process alive:

```ts theme={null}
// Worker keeps process alive (default)
worker.ref();

// Worker doesn't keep process alive
worker.unref();
```

## Worker Scope

### Global Objects

Inside a worker:

```ts theme={null}
console.log(self); // WorkerGlobalScope
console.log(self.name); // Worker name if provided

// No window or document
console.log(typeof window); // undefined
console.log(typeof document); // undefined
```

### Available APIs

Workers have access to:

* `console`
* `setTimeout`, `setInterval`, `setImmediate`
* `fetch`, `WebSocket`
* `crypto`, `TextEncoder`, `TextDecoder`
* `URL`, `URLSearchParams`
* `Blob`, `File`, `FormData`
* `ReadableStream`, `WritableStream`
* Import maps and ES modules

### Not Available

* DOM APIs (document, window)
* Most Bun-specific APIs (Bun.serve, etc.)
* Process-level APIs (process.exit)

## Import Maps in Workers

Workers support import maps:

```ts theme={null}
// Main thread
const worker = new Worker("worker.ts", {
  type: "module",
});

// worker.ts can use imports
import { helper } from "./utils.ts";
import lodash from "lodash";
```

## TypeScript

Bun automatically transpiles TypeScript in workers:

```ts theme={null}
// worker.ts
interface Task {
  id: number;
  payload: unknown;
}

self.onmessage = (event: MessageEvent<Task>) => {
  const { id, payload } = event.data;
  // Type-safe code
};
```

## Nested Workers

Workers can create other workers:

```ts theme={null}
// worker.ts
const subWorker = new Worker("sub-worker.ts");

subWorker.postMessage({ task: "process" });

subWorker.onmessage = (event) => {
  // Forward result to main thread
  self.postMessage(event.data);
};
```

## Common Patterns

### Worker Pool

```ts theme={null}
class WorkerPool {
  workers: Worker[] = [];
  queue: Array<{ data: any; resolve: Function }> = [];
  
  constructor(size: number, script: string) {
    for (let i = 0; i < size; i++) {
      const worker = new Worker(script);
      worker.onmessage = (event) => {
        const next = this.queue.shift();
        if (next) {
          worker.postMessage(next.data);
        }
      };
      this.workers.push(worker);
    }
  }
  
  async run(data: any): Promise<any> {
    return new Promise((resolve) => {
      const worker = this.workers.find(w => /* is idle */);
      if (worker) {
        worker.postMessage(data);
      } else {
        this.queue.push({ data, resolve });
      }
    });
  }
  
  terminate() {
    this.workers.forEach(w => w.terminate());
  }
}

const pool = new WorkerPool(4, "worker.ts");

for (let i = 0; i < 100; i++) {
  await pool.run({ task: i });
}

pool.terminate();
```

### Request-Response Pattern

```ts theme={null}
// Main thread
let messageId = 0;
const pending = new Map();

worker.onmessage = (event) => {
  const { id, result, error } = event.data;
  const { resolve, reject } = pending.get(id);
  pending.delete(id);
  
  if (error) reject(error);
  else resolve(result);
};

function request(data: any): Promise<any> {
  return new Promise((resolve, reject) => {
    const id = messageId++;
    pending.set(id, { resolve, reject });
    worker.postMessage({ id, data });
  });
}

const result = await request({ type: "compute", value: 42 });

// Worker
self.onmessage = async (event) => {
  const { id, data } = event.data;
  
  try {
    const result = await processData(data);
    self.postMessage({ id, result });
  } catch (error) {
    self.postMessage({ id, error: error.message });
  }
};
```

### Progress Updates

```ts theme={null}
// Worker
self.onmessage = async (event) => {
  const total = event.data.items.length;
  
  for (let i = 0; i < total; i++) {
    await processItem(event.data.items[i]);
    
    // Send progress
    self.postMessage({
      type: "progress",
      current: i + 1,
      total,
    });
  }
  
  self.postMessage({ type: "complete" });
};

// Main thread
worker.onmessage = (event) => {
  if (event.data.type === "progress") {
    const pct = (event.data.current / event.data.total) * 100;
    console.log(`Progress: ${pct.toFixed(1)}%`);
  } else if (event.data.type === "complete") {
    console.log("Done!");
  }
};
```

## Performance Considerations

### When to Use Workers

Good use cases:

* CPU-intensive computations
* Parsing large data files
* Image/video processing
* Cryptographic operations
* Parallel data processing

Not ideal for:

* I/O operations (use async instead)
* Simple computations (overhead not worth it)
* DOM manipulation (not available in workers)

### Minimizing Communication

Message passing has overhead:

```ts theme={null}
// Bad - many small messages
for (let i = 0; i < 1000; i++) {
  worker.postMessage({ index: i });
}

// Good - batch messages
worker.postMessage({ items: Array.from({ length: 1000 }, (_, i) => i) });
```

### Using Transfers

Transfer large buffers instead of cloning:

```ts theme={null}
// Slow - clones 100MB
const data = new Uint8Array(100 * 1024 * 1024);
worker.postMessage({ data });

// Fast - transfers ownership
worker.postMessage({ data }, [data.buffer]);
```

## Debugging Workers

```ts theme={null}
// Named workers help identify threads
const worker = new Worker("worker.ts", { name: "ImageProcessor" });

// Use console.log in workers
self.onmessage = (event) => {
  console.log("Worker received:", event.data);
};

// Catch errors
worker.onerror = (event) => {
  console.error(`Error in ${event.filename}:${event.lineno}`);
  console.error(event.message);
};
```

## Compatibility

Bun's Web Workers are compatible with:

* Browsers (Chrome, Firefox, Safari, Edge)
* Deno
* Cloudflare Workers (with some limitations)

## Differences from Node.js

Bun implements the standard Web Workers API, not Node.js `worker_threads`:

```ts theme={null}
// Bun (Web Workers)
const worker = new Worker("worker.ts");

// Node.js (worker_threads)
const { Worker } = require('worker_threads');
const worker = new Worker('./worker.js');
```

Migration tips:

* Use `postMessage` instead of `parentPort.postMessage`
* Use `self.onmessage` instead of `parentPort.on('message')`
* No `workerData` - pass data via `postMessage`
