After this lesson, you will be able to: Run Node in production: process managers (PM2), clustering, memory profiling, graceful shutdown.
Node app + production = these four concerns. Without them you ship hot-mess infra.
PM2: classic process manager. Restart on crash, log rotation, multiple instances per core. Node's cluster module: built-in multi-process fork (one per CPU). Modern hosts (Docker, Kubernetes, Fargate, Vercel Functions) handle process management themselves, PM2 becomes optional. Default in 2026: one Node process per container, host orchestrator handles scaling.
Without this, deploys drop in-flight requests.
import { createServer } from "node:http";import express from "express";const app = express();const server = createServer(app);server.listen(3000);let shuttingDown = false;app.get("/health", (_req, res) => {res.status(shuttingDown ? 503 : 200).json({ ok: !shuttingDown });});async function shutdown() {if (shuttingDown) return;shuttingDown = true;console.log("draining...");server.close(() => {console.log("closed");process.exit(0);});setTimeout(() => process.exit(1), 30_000); // hard exit after 30s}process.on("SIGTERM", shutdown);process.on("SIGINT", shutdown);
Memory leaks: usually long-lived listeners not removed; closures holding references; unbounded caches. Tools: `--inspect` flag → Chrome DevTools → Memory + Performance tabs. Heap snapshots: `process.kill -SIGUSR2 <pid>` (with --heap-prof or third-party tools). Production: monitor RSS + heap via process.memoryUsage(); alert on growth trend.
Every prod app needs these.
// Health endpoint (load balancer probes this)app.get("/health", async (_req, res) => {try {await db.$queryRaw`SELECT 1`;res.json({ ok: true });} catch (e) {res.status(503).json({ ok: false, error: "db" });}});// Request logging (pino is the standard)import pino from "pino";const log = pino({ level: process.env.LOG_LEVEL ?? "info" });app.use((req, _res, next) => {log.info({ method: req.method, url: req.url }, "req");next();});// Metrics: prom-client for Prometheus, OpenTelemetry for traces.
No SIGTERM handler. Deploys drop connections. console.log everywhere. Use pino (structured JSON). Trusting /health that returns 200 when DB is down. Check downstream dependencies. Unbounded in-memory caches. Heap grows forever.
Pick the cleanest answer.
Sign in and purchase access to unlock this lesson.