Skip to content
Back to Deployment

Deploying Express.js Apps

Production Node.js Express servers with PM2, Docker, or serverless adapters, plus clustering and graceful shutdown.

PlatformsIntermediate

Why

Express is the most battle-tested Node.js web framework with the largest middleware ecosystem. Deploying it as a long-running Node process (PM2/Docker) gives full control over the runtime, unlike serverless which has cold starts and timeout limits.

When

Use Express for REST APIs, BFF layers, and apps needing WebSockets or long-running tasks. Avoid for edge deploys — use Hono instead.

How

1. Build — tsc or esbuild to compile TS to dist/ 2. PM2 — pm2 start dist/server.js -i max (cluster mode, all cores) 3. Docker — node:20-alpine image, CMD ["node", "dist/server.js"] 4. Serverless — @vendia/serverless-express adapter for Lambda 5. Clustering — use cluster module or PM2 for multi-core utilization 6. Graceful shutdown — listen SIGTERM, close server, exit cleanly 7. Reverse proxy — Nginx/Caddy in front for TLS, rate limiting, static

Example

// src/server.ts — Express with graceful shutdown import express from "express"; const app = express(); app.get("/health", (req, res) => res.json({ ok: true })); const server = app.listen(3000, () => console.log("listening :3000")); process.on("SIGTERM", () => { server.close(() => process.exit(0)); }); // ecosystem.config.js — PM2 cluster module.exports = { apps: [{ name: "api", script: "dist/server.js", instances: "max", exec_mode: "cluster", max_memory_restart: "500M", }], }; // Dockerfile FROM node:20-alpine WORKDIR /app COPY dist/ ./dist/ COPY node_modules/ ./node_modules/ EXPOSE 3000 CMD ["node", "dist/server.js"]

Common Problems

  • ⚠Single core only — no cluster mode, one Node process can't use multi-core CPU
  • ⚠Memory leak crashes — no max_memory_restart, OOM kills process with no restart
  • ⚠Dropped connections on deploy — no graceful shutdown, in-flight requests terminated

Best Practices

  • ✓Use PM2 cluster mode or Node cluster — Express is single-threaded, need multiple processes for multi-core
  • ✓Always implement graceful shutdown on SIGTERM — drain connections before exit for zero-downtime deploys
  • ✓Set up health checks and graceful shutdown — handle SIGTERM to drain in-flight requests before exit

FAQ