worker_threads in Node.js
What worker_threads is
worker_threads is a built-in Node.js module
that lets you run JavaScript code on separate threads (workers).
In other words: it's a way to run several JS tasks in parallel, using different CPU cores, without blocking the main thread (the event loop).
Why it's needed
Node.js handles asynchronous I/O (network, files, databases) beautifully. But if code runs a CPU-intensive task (for example, encryption, parsing, image processing), it blocks the event loop, and the server stops responding to other requests.
The fix: offload heavy computation to separate threads using worker_threads.
1. How to load it
The module is built into Node.js (since version 10.5, stable from 12):
const { Worker, isMainThread, parentPort } = require('worker_threads');2. The simplest example
main.js
const { Worker } = require('worker_threads');
console.log('Main thread:', process.pid);
const worker = new Worker('./worker.js');
worker.on('message', msg => console.log('Result from worker:', msg));
worker.on('exit', () => console.log('Worker finished'));worker.js
console.log('Worker started:', process.pid);
let sum = 0;
for (let i = 0; i < 1e9; i++) sum += i;
postMessage(sum); // Send the result to the main threadWhat happens:
main.jsstarts a worker on a separate thread.- The worker runs a heavy task (a loop over a billion iterations).
- The main thread is not blocked.
- Once the task finishes, the result comes back as a message.
3. How data exchange works
Threads have no shared context (unlike multi-process languages). They exchange messages (message passing).
| Mechanism | Example |
|---|---|
parentPort.postMessage(data) | The worker sends a message to the main thread |
worker.on('message', handler) | The main thread listens for the reply |
workerData | Data can be passed when the worker is created |
An example of passing arguments:
const { Worker } = require('worker_threads');
const worker = new Worker('./worker.js', {
workerData: { iterations: 1e7 }
});worker.js
const { workerData, parentPort } = require('worker_threads');
let sum = 0;
for (let i = 0; i < workerData.iterations; i++) sum += i;
parentPort.postMessage(sum);4. An async version (via a promise)
For convenience, Worker can be wrapped in a promise:
const { Worker } = require('worker_threads');
function runWorker(path, data) {
return new Promise((resolve, reject) => {
const worker = new Worker(path, { workerData: data });
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', code => {
if (code !== 0) reject(new Error(`Worker stopped with code ${code}`));
});
});
}
(async () => {
const result = await runWorker('./task.js', { n: 1e8 });
console.log('Result:', result);
})();5. When to use worker_threads
| Good for | Not good for |
|---|---|
| CPU-intensive tasks | Ordinary I/O (HTTP, files, databases) |
| Parsing and processing large data | Simple API requests |
| Encryption, compression | Asynchronous I/O |
| Rendering, PDF/image generation | Simple logic |
6. How it differs from other approaches
| Approach | Module | Process or thread | Data exchange |
|---|---|---|---|
| worker_threads | worker_threads | Thread (shared memory) | Fast, via messages |
| cluster | cluster | Separate Node.js processes | IPC (slower) |
| child_process | child_process | A separate process | Via stdout/stdin |
worker_threads runs in the same process, but on a separate JS thread,
which makes it lighter and faster than cluster or child_process processes.
7. Additional capabilities
- You can use SharedArrayBuffer for shared memory.
- You can pass Transferable objects (ArrayBuffer, MessagePort).
- Atomics are supported for synchronizing data.
- TypeScript and ES Modules support both work fully.
8. Worth remembering
- Worker threads don't share a common
globalorrequire, each has its own context. - Too many workers means significant memory and communication overhead.
- A worker doesn't make Node.js "multi-threaded" in the usual sense, you decide when to create threads.
Summary
| Criterion | Description |
|---|---|
| Purpose | Running JS code in parallel on separate threads |
| Module | worker_threads |
| Data exchange | Via postMessage / parentPort |
| Performance | Lighter and faster than processes |
| Good for | CPU-intensive tasks (math, parsing, encryption) |
| Introduced | In Node.js 10.5 (stable since 12+) |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.