Zero‑Downtime Reloads with PM2 Cluster Mode: When to Use It and How to Test It
PM2 cluster mode can keep your Node.js API online while you reload workers one at a time. Learn how to enable it, test zero‑downtime reloads, and understand the trade‑offs for long‑lived connections.
01 Jul 2025, 05:27 UTC

Why Cluster Mode Matters for Node.js APIs
Stateless HTTP services that sit behind a load balancer often need to keep running while new code is deployed. The classic “stop‑all‑workers, start‑new‑workers” approach can cause a brief outage. PM2’s cluster mode and reload command let you replace workers one by one, keeping the master process alive and routing new connections to the fresh workers. This is especially useful for high‑traffic REST endpoints where each request is short‑lived and can be dropped safely if a worker is being refreshed.
How PM2 Cluster Mode Works
Internally PM2 uses Node’s cluster module. A single master process spawns n worker processes. The operating system’s TCP stack distributes incoming sockets to workers in a round‑robin fashion. Because each worker runs a separate Node.js instance, you get true CPU parallelism on multi‑core machines.
In ecosystem.config.js you enable it with:
module.exports = {
apps: [
{
name: 'api',
script: 'app.js',
exec_mode: 'cluster',
instances: 'max', // or 0 to auto‑detect CPUs
env: {
NODE_ENV: 'production'
}
}
]
};
After pm2 start ecosystem.config.js, pm2 list will show several instances labeled api:0, api:1, etc. Each instance is a worker; the master is invisible in the list.
Graceful Reload vs Restart
pm2 restart all kills every worker and spawns new ones immediately. During that brief interval the master stops accepting new connections, so a client may get a connection reset. pm2 reload all, on the other hand, sends SIGINT to a worker, lets it finish in‑flight requests, and only then starts a replacement. While a worker is shutting down, the master continues to accept connections and forwards them to the remaining live workers.
Key points:
- Reload is safe for short‑lived HTTP requests.
- Restart is faster but can drop traffic.
- Both rely on the application to handle
SIGINTgracefully.
Handling Long‑Lived Connections
WebSocket or HTTP/2 streams that stay open across multiple requests are not automatically preserved during a reload. PM2 can be configured for sticky sessions so that a client’s IP is always routed to the same worker. However, the worker that handles the established connection will still be terminated during reload, so the connection will drop unless your application implements its own reconnection logic.
To enable sticky sessions you can add:
module.exports = {
apps: [
{
name: 'api',
script: 'app.js',
exec_mode: 'cluster',
instances: 'max',
node_args: '--max-old-space-size=512',
// PM2 sticky session support
watch: false,
env: {},
// Enable sticky sessions via the built‑in option
// (requires PM2 >= 4.5.0)
// See PM2 docs for full config
// sticky: true
}
]
};
Note: sticky sessions only affect how new connections are routed; they do not keep an existing socket alive during a worker restart.
Practical Test to Verify Zero‑Downtime
- Start the app:
pm2 start ecosystem.config.js. - Confirm clustering:
pm2 listshould show multipleapi:*instances. - Generate traffic: In a separate terminal run:
This spawns a continuous stream of short GET requests.while true; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000; done - Reload workers: Execute
pm2 reload allwhile the loop runs. - Observe the output: The curl loop should continue to return
200without interruption. If you see503or connection resets, the app is not handlingSIGINTcorrectly. - Check logs:
pm2 logs apiwill show shutdown and startup messages for each worker, confirming sequential replacement.
Limitations and Trade‑offs
- Memory overhead: Each worker is a full Node.js process; with many cores you may hit RAM limits.
- Stateful workloads: Background jobs that rely on in‑process state (e.g., in‑memory caches) should stay in single‑process mode because cluster workers do not share memory.
- Version sensitivity: The exact behavior of graceful reloads and sticky sessions can differ between PM2 and Node.js releases. Always test against the specific versions you will run in production.
- Blocking code: If your handler performs blocking operations that do not return to the event loop, the worker may not exit promptly on
SIGINT, causing reload to stall.
Takeaway
Use PM2 cluster mode with reload for stateless HTTP APIs that need to stay online during deployments. Verify graceful shutdown by running continuous requests and reloading workers. Keep long‑lived connections in mind and consider sticky sessions or external load‑balancing strategies if you need to preserve them.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.