Worker, 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 a minimal version of the Web Workers API with extensions that make it work better for server-side use cases. Like the rest of Bun, Worker supports CommonJS, ES modules, TypeScript, JSX, and TSX with no extra build step.
Creating a Worker
Like in browsers, Worker is a global. Use it to create a new worker thread.
From the main thread
Worker thread
worker.ts
self, add this line to the top of your worker file.
import and export syntax in your worker code. Unlike in browsers, you don’t need to pass {type: "module"} to use ES modules.
To simplify error handling, Bun resolves the worker’s script when new Worker(url) is called.
Worker is resolved relative to the project root (like typing bun ./path/to/file.js).
preload - load modules before the worker starts
Pass an array of module specifiers to the preload option to load them before the worker’s own code runs, like the --preload CLI argument. Use it for code that must load first, such as OpenTelemetry, Sentry, or DataDog.
preload option:
blob: URLs
You can also pass a blob: URL to Worker to create a worker from a string or other in-memory source.
blob: URLs support TypeScript, JSX, and other file types. To tell Bun the source is TypeScript, set the type on the Blob or pass a filename to the File constructor.
"open"
The "open" event is emitted when a worker is created and ready to receive messages. (This event does not exist in browsers.)
"open" event before sending.
Messages with postMessage
To send messages, use worker.postMessage and self.postMessage. Messages are serialized with the HTML Structured Clone Algorithm.
Performance optimizations
Bun has fast paths forpostMessage with common data types:
String fast path - When posting a pure string, Bun bypasses the structured clone algorithm entirely, so there is no serialization overhead.
Simple object fast path - For plain objects containing only primitive values (strings, numbers, booleans, null, undefined), Bun stores properties directly without full structured cloning.
The simple object fast path activates when the object:
- Is a plain object with no prototype chain modifications
- Contains only enumerable, configurable data properties
- Has no indexed properties or getter/setter methods
- All property values are primitives or strings
postMessage performs 2-241x faster because the message length no longer has a meaningful impact on performance.
Bun (with fast paths):
message event handler on the worker and main thread.
Terminating a worker
AWorker instance terminates automatically once its event loop has no work left to do. Attaching a "message" listener on the global or any MessagePorts keeps the event loop alive. To forcefully terminate a Worker, call worker.terminate().
worker.terminate() makes the worker exit as soon as possible.
process.exit()
A worker can terminate itself with process.exit(). This does not terminate the main process. Like in Node.js, process.on('beforeExit', callback) and process.on('exit', callback) are emitted on the worker thread (and not on the main thread), and the exit code is passed to the "close" event.
"close"
The "close" event is emitted when a worker has been marked as terminated; the worker itself can take some time to fully exit. The CloseEvent contains the exit code passed to process.exit(), or 0 if it closed for another reason.
Managing lifetime
By default, an activeWorker keeps the main (spawning) process alive, so async tasks like setTimeout and promises keep the process alive. Attaching message listeners also keeps the Worker alive.
worker.unref()
To stop a running worker from keeping the process alive, call worker.unref(). This decouples the worker’s lifetime from the main process’s, matching the behavior of Node.js’ worker_threads.
worker.unref() is not available in browsers.
worker.ref()
To keep the process alive until the Worker terminates, call worker.ref(). Workers are ref’d by default; a ref’d worker still needs something on its event loop (such as a "message" listener) to continue running.
options object to Worker:
worker.ref() is not available in browsers.
Memory usage with smol
Bun’s Worker supports a smol mode that reduces memory usage at a cost of performance. To enable it, pass smol: true in the Worker constructor’s options object.
What does `smol` mode actually do?
What does `smol` mode actually do?
Setting
smol: true sets JSC::HeapSize to be Small instead of the default Large.Environment Data
Share data between the main thread and workers usingsetEnvironmentData() and getEnvironmentData().
Worker Events
Listen for worker creation events usingprocess.emit():
Bun.isMainThread
Check Bun.isMainThread to tell whether you’re on the main thread.