Worker Threads
The worker_threads module allows Node.js to run JavaScript in parallel on separate threads. Workers have their own V8 instance and event loop but can share memory via SharedArrayBuffer.
Worker threads = hiring contractors who each bring their own toolbox (V8 isolate) and work in separate rooms. They pass notes through a mail slot (postMessage). SharedArrayBuffer is a whiteboard in the hallway everyone can read/write—but you need locks (Atomics) or they'll scribble over each other.
Workers are appropriate for CPU-bound tasks (image processing, cryptography, ML inference) that would block the main thread. Communication between workers and the main thread uses MessageChannel (postMessage/on('message')), with data structured-cloned by default (copied). SharedArrayBuffer with Atomics enables zero-copy shared memory and atomic operations for synchronization. Workers can also use workerData for initial configuration passed at construction.
Creating a worker has significant overhead (~50ms startup, ~30MB memory per worker) due to spinning up a full V8 isolate. Worker pools (reusing workers across tasks) are essential for latency-sensitive workloads—libraries like piscina implement this efficiently. Transferable objects (ArrayBuffer, MessagePort) transfer ownership to the receiver with zero-copy semantics, avoiding the structured-clone overhead for large buffers. Workers cannot access the DOM (irrelevant server-side) or require native addons that aren't thread-safe. SharedArrayBuffer requires cross-origin isolation headers in browser contexts (COOP/COEP) but has no such restriction in Node.js.
Worker threads run JavaScript in parallel with true OS thread parallelism. Each worker has its own V8 isolate and event loop, communicating via postMessage (structured clone) or SharedArrayBuffer (zero-copy shared memory). Use workers for CPU-bound tasks to prevent event loop blocking. Worker creation is expensive (~50ms, ~30MB); use a worker pool (piscina) for high-frequency task execution.
postMessage performs a structured clone of transferred data, which is O(n) in data size. Passing a 100MB Buffer between workers via postMessage copies 100MB synchronously on the sending thread—blocking the event loop for potentially hundreds of milliseconds. Always transfer ownership with the transfer list: `postMessage(buffer, [buffer])` for zero-copy transfer.