Skip to main content

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):

javascript
const { Worker, isMainThread, parentPort } = require('worker_threads');

2. The simplest example

main.js

javascript
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

javascript
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 thread

What happens:

  • main.js starts 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).

MechanismExample
parentPort.postMessage(data)The worker sends a message to the main thread
worker.on('message', handler)The main thread listens for the reply
workerDataData can be passed when the worker is created

An example of passing arguments:

javascript
const { Worker } = require('worker_threads'); const worker = new Worker('./worker.js', { workerData: { iterations: 1e7 } });

worker.js

javascript
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:

javascript
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 forNot good for
CPU-intensive tasksOrdinary I/O (HTTP, files, databases)
Parsing and processing large dataSimple API requests
Encryption, compressionAsynchronous I/O
Rendering, PDF/image generationSimple logic

6. How it differs from other approaches

ApproachModuleProcess or threadData exchange
worker_threadsworker_threadsThread (shared memory)Fast, via messages
clusterclusterSeparate Node.js processesIPC (slower)
child_processchild_processA separate processVia 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 global or require, 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

CriterionDescription
PurposeRunning JS code in parallel on separate threads
Moduleworker_threads
Data exchangeVia postMessage / parentPort
PerformanceLighter and faster than processes
Good forCPU-intensive tasks (math, parsing, encryption)
IntroducedIn Node.js 10.5 (stable since 12+)

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.