Deploying Node.js Apps
Deployment is everything between "it works on my laptop" and "users can reach it reliably on the internet." A Node app in production is a different beast: it must survive crashes, use all the CPU cores, sit behind a proxy that terminates TLS, read its config from the environment, shut down gracefully, and be observable when something goes wrong. This page is the map for the section — the gap between dev and prod, the main hosting models (PaaS, containers, VMs, serverless), the anatomy of a typical production stack, and the deployment workflow — before later pages dive into PM2, Nginx, Docker, the cloud, and CI/CD.
What changes from dev to production
Concern | Development | Production |
|---|---|---|
Process | One | Supervised, auto-restart, multi-core (PM2/cluster) |
TLS / HTTPS | Usually plain HTTP | TLS terminated at a proxy or load balancer |
Config |
| Injected env vars / secrets manager |
|
|
|
Errors | Full stack traces to screen | Logged & monitored; generic message to users |
Crashes | You notice and restart | Supervisor restarts; alerting fires |
Static assets | Served by Node | Served by CDN / proxy |
Hosting models
Model | You manage | Examples | Best for |
|---|---|---|---|
PaaS | Just your code | Render, Railway, Fly.io, Heroku | Fastest path to live; small/medium apps |
Containers | Image + orchestration | Docker + Kubernetes/ECS | Portability, scale, complex systems |
VMs / bare metal | OS, runtime, everything | EC2, DigitalOcean droplet | Full control; legacy/specific needs |
Serverless | Just a function | Lambda, Cloud Functions | Spiky/low traffic, event-driven, no ops |
Anatomy of a typical production stack
Internet │ HTTPS ▼ [ Load balancer / CDN ] ← TLS termination, static assets, DDoS edge │ HTTP (internal) ▼ [ Reverse proxy: Nginx ] ← routing, gzip, rate limiting, buffering │ ▼ [ Node processes × N cores ] ← PM2 / cluster / container replicas (stateless) │ │ ▼ ▼ [ Database ] [ Redis cache / queue ] ← shared state lives HERE, not in Node
The deployment workflow
Build — install production dependencies, compile TypeScript, produce the runnable artifact (a
dist/or a Docker image).Test & check — run tests, lint, and type-check in CI; a red build never deploys.
Configure — supply environment variables / secrets for the target environment; set
NODE_ENV=production.Release — push the artifact to the host (PaaS, registry, server) and start it under a process manager.
Migrate — run database migrations as a controlled step, ordered safely relative to the code rollout.
Verify — confirm health checks pass and key paths work before sending real traffic (and be ready to roll back).
Observe — watch logs, metrics, and error rates after release; alert on regressions.