Skip to main content
The Worker API is still experimental, particularly around worker termination. Bun is actively working on improving this.
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 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

index.ts

Worker thread

worker.ts
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.
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 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.
Listen for messages using event listeners:

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.

Worker lifecycle events

”open”

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

”close”

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

Terminating workers

A worker terminates automatically when its event loop has no more work. To forcefully terminate a worker:
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:
You can also set this via the constructor:

worker.ref()

Re-attach the worker to the main process lifetime:
worker.ref() and worker.unref() are Bun extensions and are not available in browsers.

Checking the current thread

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

Sharing environment data

Share data from the main thread to all workers using setEnvironmentData and getEnvironmentData from worker_threads:
index.ts
worker.ts

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:

blob: URLs

You can create a worker from an inline string using a blob: URL:
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:
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"):

SharedArrayBuffer and Atomics

For true shared memory between threads, use SharedArrayBuffer with Atomics for synchronization:
index.ts
worker.ts
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.

Node.js worker_threads compatibility

Bun is compatible with Node.js’s worker_threads module: