How to Implement Graceful Shutdown in a Node.js Server
A graceful shutdown lets your Node.js server stop accepting new requests, finish the ones already in progress, close its database connections, and then exit cleanly — instead of being killed mid-request. It is essential for zero-downtime deploys and for not dropping users' work.
Why it matters
When you deploy or restart, the process receives a termination signal. Without handling it, Node dies instantly — cutting off in-flight requests, leaving database transactions half-done, and dropping connections. Graceful shutdown avoids all of that.
The signals to handle
Listen for SIGTERM (sent by process managers and orchestrators) and SIGINT (Ctrl+C):
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
The shutdown sequence
- Stop accepting new connections — call
server.close(), which lets existing requests finish. - Finish in-flight requests —
server.close()'s callback fires once they are done. - Close resources — database pools, Redis clients, file handles.
- Exit — call
process.exit(0).
function shutdown() { server.close(() => { db.end(); redis.quit(); process.exit(0); }); }
Add a safety timeout
If requests hang, do not wait forever — set a timeout that forces exit after, say, 10 seconds, so a stuck request cannot block the shutdown indefinitely.
Why it enables zero-downtime deploys
With graceful shutdown, PM2 reloads replace instances one at a time without dropping requests, and it pairs with proper error handling and monitoring for reliable operations.
Frequently asked questions
Which signal should I handle for deploys?
Primarily SIGTERM, which process managers and container platforms send to ask your app to stop. Also handle SIGINT for local Ctrl+C during development.
What if a request never finishes?
Add a forced-exit timeout so a hung request cannot block shutdown forever. After the grace period, exit anyway — better than hanging indefinitely.
Do I need this with PM2?
Yes — PM2's zero-downtime reloads rely on your app shutting down gracefully on SIGTERM. Without it, reloads can still drop in-flight requests.
Was this article helpful?