Runtime Ops Basics
10 examples for operating long-lived Node.js 24 processes in production - 7 basic and 3 intermediate.
Search across all documentation pages
10 examples for operating long-lived Node.js 24 processes in production - 7 basic and 3 intermediate.
mkdir prod-api && cd prod-api
npm init -y
npm pkg set type=module
npm install express@5 pg
npm install -D typescript@5.6 @types/nodeFor shutdown and deploy patterns, see Graceful Shutdown and Zero-Downtime Deploys.
Kubernetes / ECS / systemd / PM2
-> starts `node dist/main.js`
-> restarts on crash exit code != 0
-> sends SIGTERM on deploy or scale-in
-> reads stdout logs
console.log(JSON.stringify({
event: "boot",
node: process.version,
env: process.env.NODE_ENV,
pid: process.pid,
}));app.get("/health", (_req, res) => res.json({ status: "ok" }));
app.get("/ready", async (_req, res) => {
const ok = await pool.query("SELECT 1");
res.status(ok ? 200 : 503).json({ status: ok ? "ready" : "not_ready" });
});uncaughtException Policyprocess.on("uncaughtException", (err) => {
console.error(JSON.stringify({ event: "uncaughtException", message: err.message, stack: err.stack }));
// Policy A: exit and let supervisor restart (recommended for APIs)
process.exit(1);
});unhandledRejection Policyprocess.on("unhandledRejection", (reason) => {
console.error(JSON.stringify({ event: "unhandledRejection", reason: String(reason) }));
process.exit(1);
});app.get("/metrics/memory", (_req, res) => {
const m = process.memoryUsage();
res.json({
rss: m.rss,
heapUsed: m.heapUsed,
heapTotal: m.heapTotal,
external: m.external,
});
});nodejs_heap_size_bytes exporter for real monitoringNODE_OPTIONS Heap CapNODE_OPTIONS="--max-old-space-size=384"const server = app.listen(port, "0.0.0.0");
function shutdown(signal: string) {
console.log(JSON.stringify({ event: "shutdown", signal }));
server.close(async () => {
await pool.end();
process.exit(0);
});
setTimeout(() => process.exit(1), 30_000).unref();
}
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));// ecosystem.config.cjs
module.exports = {
apps: [{
name: "api",
script: "dist/main.js",
instances: 2,
exec_mode: "cluster",
max_memory_restart: "512M",
kill_timeout: 30_000,
listen_timeout: 10_000,
}],
};pm2 start ecosystem.config.cjs
pm2 save| Symptom | Check |
|---|---|
| High CPU | Recent deploy? Traffic spike? Infinite loop in logs? |
| High memory | Heap leak? max-old-space-size vs limit? |
| 502 from LB | Pods ready? SIGTERM drain? Upstream timeout? |
kubelet + Deployment controller. Your app handles SIGTERM; K8s restarts failed containers.
No. Scale pod replicas instead of Node cluster module inside one container.
Under terminationGracePeriodSeconds (often 30-45s). Match LB deregistration delay + DB pool close.
Stdout only. Agents ship logs off-node.
Node 24 LTS, matching CI and Docker base image.
Platform deploy is where/how you run containers. Runtime ops is how the Node process behaves once running.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 16, 2026