A single Node.js process uses one CPU core for JavaScript, so a multi-core machine is underused. The cluster module forks worker processes that share a server port, letting the OS distribute connections across cores. Each worker is a separate process, so state is not shared.
Before you start
You should be comfortable with the Node.js HTTP server and process model. This article covers clustering; process managers and containers offer similar behavior at a higher level.
Step-by-step walkthrough
Step 1: Fork one worker per core
In the primary process, fork a worker for each available core using os.availableParallelism(). Workers call listen on the same port, and the primary distributes incoming connections, so the load spreads across cores without a separate port.
Step 2: Restart crashes and drain gracefully
Listen for the exit event and fork a replacement, but bound restarts so a crash loop does not spawn endlessly. On shutdown, signal workers to stop accepting new connections and finish in-flight requests before exiting.
Step 3: Keep state out of the process
Because workers are separate processes, in-memory state such as a session store or cache is not shared or consistent across them. Move shared state to an external store, and note that sticky sessions may be needed for session affinity.
Worked scenario
The primary forks workers and replaces any that exit.
import cluster from 'node:cluster';
import os from 'node:os';
if (cluster.isPrimary) {
for (let i = 0; i < os.availableParallelism(); i += 1) cluster.fork();
cluster.on('exit', () => cluster.fork());
} else {
// start the HTTP server in each worker
}Walk through the example
The primary creates one worker per core and shares the listening socket, so a request may be handled by any worker. When a worker exits, a new one is forked, keeping capacity steady. Because each worker has its own memory, a cache in one worker is invisible to the others, which is the constraint to design around.
Common mistake
Storing sessions in a worker’s memory, so a user’s next request may hit a different worker and lose the session. Another is unlimited restart on a crash loop, which floods the system with failing processes.
Verify the behavior
Log the worker id per request and confirm requests spread across workers. Kill a worker and confirm a replacement starts and traffic continues. Set an in-memory value in one worker and confirm it is absent in another, proving state is not shared.
Interview exercise
Why can clustering break an in-memory session store?
Answer and reasoning
Each worker is a separate process with its own memory, so a session written in one worker does not exist in another. When the next request lands on a different worker, the session appears missing, logging the user out. The fix is a shared external store such as Redis, or sticky routing that always sends a user to the same worker.
Continue learning
Compare scaling tools in Worker threads and Graceful shutdown. Read the Node.js cluster documentation and try the Node.js interview questions.