Worker Threads: True Parallelism in Node.js
12 min read
Worker Threads
Node.js is single-threaded by default, but the worker_threads module lets you spawn OS threads that share memory via SharedArrayBuffer. Unlike child_process, worker threads live inside the same process and have low spawn overhead, making them ideal for CPU-intensive tasks.
Spawning a Worker
js
// main.js
const { Worker } = require("worker_threads");
function runWorker(data) {
return new Promise((resolve, reject) => {
const worker = new Worker("./worker.js", { workerData: data });
worker.on("message", resolve);
worker.on("error", reject);
worker.on("exit", (code) => {
if (code !== 0) reject(new Error(`Worker exited with code ${code}`));
});
});
}
async function main() {
const result = await runWorker({ n: 40 });
console.log("Fibonacci(40) =", result); // 102334155
}
main();js
// worker.js
const { workerData, parentPort } = require("worker_threads");
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
parentPort.postMessage(fib(workerData.n));Shared Memory with SharedArrayBuffer
js
// Share a typed array between main thread and worker
const { Worker, isMainThread, workerData } = require("worker_threads");
if (isMainThread) {
const sharedBuffer = new SharedArrayBuffer(4); // 4 bytes = 1 Int32
const arr = new Int32Array(sharedBuffer);
arr[0] = 0;
const w = new Worker(__filename, { workerData: { sharedBuffer } });
w.on("exit", () => console.log("Counter:", arr[0])); // 1000
} else {
const arr = new Int32Array(workerData.sharedBuffer);
for (let i = 0; i < 1000; i++) Atomics.add(arr, 0, 1);
}Use Atomics operations whenever multiple threads write to the same SharedArrayBuffer position — without them, concurrent writes produce race conditions and unpredictable values.
Ready to test yourself?
Practice Node.js— quiz & coding exercises