How to Handle Graceful Shutdown in Node.js: Best Practices
Node.js, listen for termination signals like SIGINT or SIGTERM and close your server and resources inside those handlers. This ensures your app finishes ongoing requests and cleans up before exiting.Why This Happens
When you stop a Node.js app abruptly (like pressing Ctrl+C), the server may close immediately without finishing current requests or cleaning resources. This can cause data loss, corrupted files, or open connections.
const http = require('http'); const server = http.createServer((req, res) => { res.end('Hello World'); }); server.listen(3000); // No shutdown handling console.log('Server running on port 3000');
The Fix
Listen for SIGINT and SIGTERM signals to detect when the app should stop. Inside these handlers, close the server and any other resources like database connections. Then exit the process after cleanup.
const http = require('http'); const server = http.createServer((req, res) => { res.end('Hello World'); }); server.listen(3000, () => { console.log('Server running on port 3000'); }); function gracefulShutdown() { console.log('Received shutdown signal, closing server...'); server.close(() => { console.log('Server closed. Exiting process.'); process.exit(0); }); // If server doesn't close in 10 seconds, force exit setTimeout(() => { console.error('Forcing shutdown'); process.exit(1); }, 10000); } process.on('SIGINT', gracefulShutdown); process.on('SIGTERM', gracefulShutdown);
Prevention
Always add signal handlers for SIGINT and SIGTERM in your Node.js apps to cleanly close servers and resources. Use server.close() to stop accepting new requests but finish ongoing ones. Set a timeout to force exit if cleanup hangs.
Use linting rules or code reviews to ensure graceful shutdown is implemented. Test shutdown behavior regularly to avoid surprises in production.
Related Errors
Developers may see errors like ECONNRESET or UnhandledPromiseRejectionWarning if shutdown is abrupt. These happen when connections close unexpectedly or async cleanup fails.
Fix these by properly awaiting async cleanup tasks and closing connections before exiting.