Node.js Cheatsheet

Cluster (Multi-Core Servers)

Use this Node.js reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

What Cluster Does

node:cluster forks the same program into multiple worker processes that share listening sockets — the standard way to use every CPU core for an HTTP server without a load balancer in front. Workers are full processes (own memory, own event loop); the primary distributes incoming connections round-robin (except on Windows).

Clustered HTTP Server

import cluster from "node:cluster";
import http from "node:http";
import os from "node:os";

if (cluster.isPrimary) {
  const cpus = os.availableParallelism();   // prefer over os.cpus().length
  console.log(`primary ${process.pid} forking ${cpus} workers`);

  for (let i = 0; i < cpus; i++) cluster.fork();

  // Restart crashed workers
  cluster.on("exit", (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died (${signal ?? code})`);
    cluster.fork();
  });
} else {
  // Every worker calls listen(3000) — the primary shares the port
  http.createServer((req, res) => {
    res.end(`handled by ${process.pid}\n`);
  }).listen(3000);
}

Primary ↔ Worker Messaging

// Primary
const worker = cluster.fork();
worker.send({ cmd: "config", value: 42 });
worker.on("message", (msg) => console.log("from worker:", msg));

// Broadcast to all workers
for (const id in cluster.workers) {
  cluster.workers[id].send({ cmd: "reload" });
}

// Worker
process.on("message", (msg) => { ... });
process.send({ ready: true });

Graceful Shutdown and Zero-Downtime Reload

// Primary: rolling restart — replace workers one at a time
async function rollingRestart() {
  for (const worker of Object.values(cluster.workers)) {
    const replacement = cluster.fork();
    await new Promise((r) => replacement.on("listening", r));
    worker.disconnect();                 // stop accepting, finish in-flight
    setTimeout(() => worker.kill(), 10_000).unref();  // hard deadline
  }
}

// Worker: close the server cleanly on disconnect
process.on("disconnect", () => {
  server.close(() => process.exit(0));
});

Cluster API Reference

APIWherePurpose
cluster.isPrimarybothtrue in the original process
cluster.isWorkerbothtrue in forked workers
cluster.fork(env?)primarySpawn a worker (extra env vars merged in)
cluster.workersprimary{ id: Worker } map of live workers
cluster.workerworkerThis process's Worker handle
worker.disconnect()primaryGraceful: close server, exit when idle
worker.kill(signal?)primaryForce-terminate
worker.isDead()primaryExited?
cluster.on("exit" / "listening" / "online" / "message")primaryLifecycle events

Cluster vs Alternatives

# Production processes are usually supervised externally instead:
pm2 start app.js -i max        # pm2 cluster mode (uses node:cluster inside)
docker compose up --scale app=4   # one process per container + a proxy

- State does not survive across workers — sessions, caches, and rate-limit counters must live in Redis/Postgres, not process memory. - Sticky sessions (WebSocket + multi-worker) need an external LB or pm2's sticky mode; the built-in round-robin is per-connection. - For CPU-bound work inside one server, prefer worker_threads — cheaper than a full process per task.