# How to Implement Worker Threads in Bun for Parallel Processing: Complete Guide with Examples

> Learn to implement worker threads in Bun for powerful parallel processing. This complete guide uses Bun's high-performance Web Worker foundation for efficient computation. Get started today!

- Repository: [Bun/bun](https://github.com/oven-sh/bun)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Bun implements a Node.js-compatible `worker_threads` module that spawns isolated JavaScript VMs on separate OS threads, enabling parallel computation through message passing while leveraging Bun's high-performance Web Worker foundation.**

Bun's implementation of Worker threads allows developers to utilize multi-core processors for CPU-intensive tasks without leaving the JavaScript ecosystem. Located in the `oven-sh/bun` repository, the `worker_threads` module at [`src/js/node/worker_threads.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/worker_threads.ts) provides full API compatibility with Node.js while offering additional performance optimizations specific to Bun's JavaScriptCore engine.

## Architecture of Bun’s Worker Thread Implementation

The `worker_threads` module in Bun is implemented entirely in TypeScript and serves as a thin wrapper around Bun's native **Web Worker** implementation. This architectural choice enables Node.js compatibility while maintaining the performance characteristics of Bun's JavaScriptCore runtime.

### The Worker Class Structure

The `Worker` class extends `EventEmitter` and encapsulates a native Web Worker instance (referenced as the private field `#worker`). According to lines 26-88 of [`src/js/node/worker_threads.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/worker_threads.ts), this class translates Node-style events (`message`, `error`, `close`, `online`) into the corresponding Web Worker lifecycle events. The constructor (lines 52-73) handles script loading through either file paths or inline evaluation via temporary Blob URLs when the `eval` option is enabled.

### Message Port Implementation

Bun creates a **fake `MessagePort`** for `parentPort` using the `fakeParentPort()` function (lines 30-44). This wrapper forwards `postMessage` and `onmessage` calls to the global `self` object within the worker thread, ensuring that code written for Node.js `worker_threads` functions identically in Bun without modification. This implementation activates automatically when the file detects it is not running on the main thread.

### Native Bindings and Thread State

Thread-local data including `workerData`, `threadId`, and environment mappings are injected from the native side via `$cpp("Worker.cpp","createNodeWorkerThreadsBinding")` (lines 22-33). This C++ bridge connects the JavaScript API to Bun's underlying thread management system, allowing seamless access to thread-specific information from JavaScript.

## Creating Worker Threads in Bun

### Basic Worker Creation and Messaging

To spawn a worker, import the `Worker` class from `node:worker_threads` and instantiate it with a file path. The following example demonstrates bidirectional communication between the main thread and a worker:

```typescript
// main.ts
import { Worker } from "node:worker_threads";

const worker = new Worker("./worker.ts");
worker.on("message", (msg) => console.log("Main received:", msg));
worker.postMessage({ task: "heavy computation" });

```

```typescript
// worker.ts
import { parentPort } from "node:worker_threads";

parentPort?.on("message", (data) => {
  const result = data.task.split("").reverse().join("");
  parentPort?.postMessage({ result });
});

```

### Accessing Thread Context with workerData

The `workerData` property allows you to pass initialization data to worker threads during construction. Combined with `isMainThread`, you can create self-contained modules that function as both entry points and workers:

```typescript
// compute.ts
import { Worker, isMainThread, workerData } from "node:worker_threads";

if (isMainThread) {
  // Main thread: spawn workers
  for (let i = 0; i < 4; i++) {
    new Worker(import.meta.url, {
      workerData: { workerId: i, start: i * 1000, end: (i + 1) * 1000 }
    });
  }
} else {
  // Worker thread: access initialized data
  console.log(`Worker ${workerData.workerId} processing range ${workerData.start}-${workerData.end}`);
  // Perform computation...
}

```

### Sharing Environment Data Across Threads

Use `setEnvironmentData` and `getEnvironmentData` to share configuration objects between the main thread and all spawned workers without passing them through `workerData` for each instance:

```typescript
// main.ts
import { setEnvironmentData, Worker } from "node:worker_threads";
setEnvironmentData("databaseConfig", { host: "localhost", port: 5432 });
new Worker("./db-worker.ts");

// db-worker.ts
import { getEnvironmentData } from "node:worker_threads";
const config = getEnvironmentData("databaseConfig");
console.log("Connecting to:", config.host);

```

## Worker Lifecycle and Performance Optimization

### Termination and Resource Management

Control worker lifetimes using `terminate()`, `unref()`, and `ref()`. The `terminate()` method returns a `Promise<number>` that resolves with the worker's exit code (implemented in lines 15-22 of the source):

```typescript
const worker = new Worker("./long-task.ts");
worker.unref(); // Allow process to exit even if worker is running

// Force termination after timeout
setTimeout(async () => {
  const exitCode = await worker.terminate();
  console.log(`Worker exited with code: ${exitCode}`);
}, 5000);

```

### Memory Optimization with smol Mode

For applications spawning many lightweight workers, enable the `smol` option to reduce per-worker heap size, and use `preload` to inject instrumentation or polyfills before the worker script executes:

```typescript
const worker = new Worker("./task.ts", {
  smol: true,                    // Reduce memory footprint
  preload: ["./tracing.js"]      // Load monitoring before main script
});

```

### Message Passing Performance

Bun optimizes `postMessage` for plain strings and simple objects by bypassing the full Structured Clone algorithm when possible. This fast-path optimization, documented in `docs/runtime/workers.mdx`, makes inter-thread communication significantly cheaper than standard Node.js implementations while maintaining spec compliance.

## Summary

- Bun's `worker_threads` module resides in [`src/js/node/worker_threads.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/worker_threads.ts) and wraps native Web Workers to provide Node.js API compatibility.
- The `Worker` class extends `EventEmitter` and manages OS thread lifecycle through native bindings to [`Worker.cpp`](https://github.com/oven-sh/bun/blob/main/Worker.cpp).
- **parentPort** is implemented via `fakeParentPort()` (lines 30-44), forwarding messages to the global `self` object within the worker context.
- Thread-local state (`workerData`, `threadId`) is injected through C++ bindings at `createNodeWorkerThreadsBinding` (lines 22-33).
- **Performance optimizations** include fast-path message serialization and the `smol` mode for memory-constrained environments.
- Use `unref()`/`ref()` to control process lifetime dependencies, and `terminate()` to force shutdown with exit code retrieval.

## Frequently Asked Questions

### Are Bun worker threads compatible with existing Node.js code?

Yes. Bun's implementation of `worker_threads` in [`src/js/node/worker_threads.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/worker_threads.ts) provides full API compatibility with Node.js, including `Worker`, `parentPort`, `workerData`, `isMainThread`, `MessageChannel`, `BroadcastChannel`, and environment data methods. You can migrate existing Node.js worker code to Bun without modifications to the public API surface.

### How does Bun's Worker implementation differ from Node.js?

While Node.js builds workers on top of libuv and V8 isolates, Bun implements workers as a TypeScript wrapper around its JavaScriptCore-based Web Worker engine defined in [`src/js/node/worker_threads.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/worker_threads.ts). This architecture allows Bun to optimize message passing through fast-path serialization for simple objects and provides additional options like `smol` mode for reduced memory usage per thread.

### Can I share memory between worker threads in Bun?

Yes. Bun supports `SharedArrayBuffer` and the standard `MessageChannel` API for zero-copy data sharing between threads. The `workerData` mechanism also allows passing structured cloneable data during worker initialization via the native binding layer, while `setEnvironmentData` enables process-wide configuration sharing.

### What happens when I call worker.terminate() in Bun?

The `terminate()` method immediately stops the worker thread and returns a `Promise<number>` that resolves with the worker's exit code (implementation lines 15-22). This differs from `unref()`, which merely allows the process to exit naturally without forcing the worker to stop execution or resolving with an exit status.