One Process Per CPU — Built-In Horizontal Scaling
Cluster
cluster forks your script across multiple processes, all sharing the same listening port.
What you'll learn
- Fork workers per CPU
- Share a server port across processes
- Decide when to cluster
A single Node process runs one event loop. To use all the cores
on a machine, you run multiple processes. node:cluster automates
this — and lets them share a server port.
A Clustered Server
import cluster from "node:cluster";
import { cpus } from "node:os";
import { createServer } from "node:http";
if (cluster.isPrimary) {
const n = cpus().length;
console.log(`primary spawning ${n} workers`);
for (let i = 0; i < n; i++) cluster.fork();
cluster.on("exit", (worker) => {
console.log(`worker ${worker.process.pid} died — restarting`);
cluster.fork();
});
} else {
createServer((req, res) => {
res.end(`served by pid ${process.pid}`);
}).listen(3000);
} All workers bind to port 3000. The OS distributes incoming connections round-robin. Each handles requests on its own event loop.
When to Cluster
- You’re CPU-bound on a single core
- You have multi-core hardware
- You can tolerate the per-process memory cost (a Node process is ~50MB; 8 workers = ~400MB)
For IO-bound workloads (most APIs), a single process with async IO scales fine. Don’t cluster blindly.
Modern Alternative
For real production, you usually run multiple Node containers behind a load balancer (Nginx, Cloudflare, Kubernetes). That gives you cluster’s benefit plus zero-downtime deploys, isolated failures, and easy horizontal scaling across machines.
Cluster is most useful for single-server setups (VPS, bare metal) where adding more containers is overkill.
pm2 and node:cluster
pm2 (a popular process manager) uses cluster mode by default —
no manual code needed:
pm2 start app.mjs -i max # one per core