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

# Web Workers

> Run JavaScript in parallel using Bun's Worker API — a Web-standard implementation with extensions for server-side use cases.

<Warning>
  The `Worker` API is still experimental, particularly around worker termination. Bun is actively working on improving this.
</Warning>

[`Worker`](https://developer.mozilla.org/en-US/docs/Web/API/Worker) lets you start and communicate with a new JavaScript instance running on a separate thread, while sharing I/O resources with the main thread.

Bun implements the [Web Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) with server-side extensions. Like the rest of Bun, workers support CommonJS, ES Modules, TypeScript, JSX, and TSX out of the box — no build step needed.

***

## Creating a worker

### Main thread

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

worker.postMessage({ type: "start", payload: "hello" });

worker.onmessage = event => {
  console.log(event.data);
};
```

### Worker thread

```typescript worker.ts theme={null}
declare var self: Worker;

self.onmessage = (event: MessageEvent) => {
  console.log(event.data);
  postMessage("world");
};
```

<Note>
  Add `declare var self: Worker;` to the top of your worker file to avoid TypeScript errors. Unlike in browsers, you do not need to specify `{ type: "module" }` to use ES Modules in workers.
</Note>

The specifier passed to `new Worker(url)` is resolved relative to the project root. If the file does not exist, an error is thrown immediately at construction time.

***

## Sending and receiving messages

Use [`worker.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage) to send messages to the worker, and `self.postMessage` inside the worker to send messages back. Messages are serialized using the [HTML Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).

```typescript theme={null}
// Main thread → worker
worker.postMessage({ command: "process", data: [1, 2, 3] });

// Inside the worker → main thread
postMessage({ result: "done" });
```

Listen for messages using event listeners:

```typescript theme={null}
// Worker thread
self.addEventListener("message", event => {
  console.log(event.data);
});

// Main thread
worker.addEventListener("message", event => {
  console.log(event.data);
});
```

### Performance

Bun includes fast paths for `postMessage` that dramatically improve performance for common data types:

* **String fast path** — posting a pure string bypasses structured clone entirely.
* **Simple object fast path** — plain objects containing only primitives use an optimized path.

With these fast paths, Bun's `postMessage` is **2–241x faster** than Node.js for typical payloads.

```typescript theme={null}
// Optimized: string fast path
postMessage("Hello, worker!");

// Optimized: simple object fast path
postMessage({ message: "Hello", count: 42, enabled: true });

// Standard structured clone (nested objects, Dates, buffers, etc.)
postMessage({ nested: { deep: true }, date: new Date() });
```

***

## Worker lifecycle events

### "open"

Emitted when the worker is ready to receive messages. Messages sent before this event are automatically queued.

```typescript theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href);

worker.addEventListener("open", () => {
  console.log("Worker is ready");
});
```

### "close"

Emitted when the worker has been terminated. The `CloseEvent` contains the exit code.

```typescript theme={null}
worker.addEventListener("close", event => {
  console.log("Worker closed with code:", event.code);
});
```

***

## Terminating workers

A worker terminates automatically when its event loop has no more work. To forcefully terminate a worker:

```typescript theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href);

// Some time later...
worker.terminate();
```

A worker can also terminate itself using `process.exit()`. This does not terminate the main process.

***

## Managing worker lifetime

By default, an active `Worker` keeps the main process alive.

### worker.unref()

Decouple the worker's lifetime from the main process. The main process can exit even if the worker is still running:

```typescript theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
worker.unref();
```

You can also set this via the constructor:

```typescript theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href, {
  ref: false,
});
```

### worker.ref()

Re-attach the worker to the main process lifetime:

```typescript theme={null}
worker.unref();
// later...
worker.ref();
```

<Note>
  `worker.ref()` and `worker.unref()` are Bun extensions and are not available in browsers.
</Note>

***

## Checking the current thread

Use `Bun.isMainThread` to check whether code is running on the main thread or in a worker:

```typescript theme={null}
if (Bun.isMainThread) {
  console.log("Running on the main thread");
} else {
  console.log("Running in a worker");
}
```

***

## Sharing environment data

Share data from the main thread to all workers using `setEnvironmentData` and `getEnvironmentData` from `worker_threads`:

```typescript index.ts theme={null}
import { setEnvironmentData } from "worker_threads";

setEnvironmentData("config", { apiUrl: "https://api.example.com" });

const worker = new Worker("./worker.ts");
```

```typescript worker.ts theme={null}
import { getEnvironmentData } from "worker_threads";

const config = getEnvironmentData("config");
console.log(config); // => { apiUrl: "https://api.example.com" }
```

***

## Preloading modules

Use the `preload` option to load modules before the worker script starts. This is useful for instrumentation tools like OpenTelemetry, Sentry, or DataDog:

```typescript theme={null}
const worker = new Worker("./worker.ts", {
  preload: ["./load-sentry.js"],
});
```

***

## blob: URLs

You can create a worker from an inline string using a `blob:` URL:

```typescript theme={null}
const code = `
  self.onmessage = (event) => {
    postMessage(event.data * 2);
  };
`;

const blob = new Blob([code], { type: "application/typescript" });
const url = URL.createObjectURL(blob);
const worker = new Worker(url);

worker.postMessage(21);
worker.onmessage = e => console.log(e.data); // 42
```

Workers created from `blob:` URLs support TypeScript, JSX, and other formats out of the box.

***

## Memory usage

Workers can consume significant memory. Use `smol: true` to reduce memory usage at the cost of some performance:

```typescript theme={null}
const worker = new Worker("./worker.ts", {
  smol: true,
});
```

This sets the JSC heap size to `Small` instead of `Large`.

***

## Worker events on the main process

Listen for worker creation events using `process.on("worker")`:

```typescript theme={null}
process.on("worker", worker => {
  console.log("New worker created, thread ID:", worker.threadId);
});
```

***

## SharedArrayBuffer and Atomics

For true shared memory between threads, use `SharedArrayBuffer` with `Atomics` for synchronization:

```typescript index.ts theme={null}
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);

const worker = new Worker("./worker.ts");
worker.postMessage({ buffer: sharedBuffer });

// Wait until the worker signals completion
Atomics.wait(sharedArray, 0, 0);
console.log("Worker wrote:", sharedArray[0]);
```

```typescript worker.ts theme={null}
declare var self: Worker;

self.onmessage = (event: MessageEvent) => {
  const sharedArray = new Int32Array(event.data.buffer);

  // Write a value and notify the main thread
  Atomics.store(sharedArray, 0, 42);
  Atomics.notify(sharedArray, 0, 1);
};
```

<Warning>
  `Atomics.wait()` blocks the thread. Never call it on the main thread in a browser context. In Bun server-side code, use it only in worker threads or when blocking is intentional.
</Warning>

***

## Node.js worker\_threads compatibility

Bun is compatible with Node.js's `worker_threads` module:

```typescript theme={null}
import { Worker, isMainThread, parentPort, workerData } from "worker_threads";

if (isMainThread) {
  const worker = new Worker(__filename, {
    workerData: { value: 42 },
  });

  worker.on("message", result => {
    console.log("Result:", result); // 84
  });
} else {
  parentPort?.postMessage(workerData.value * 2);
}
```
