Platform Deploy Basics
10 examples for running Node.js 24 APIs on Kubernetes, ECS, or Cloud Run using 12-factor principles - 7 basic and 3 intermediate.
Search across all documentation pages
10 examples for running Node.js 24 APIs on Kubernetes, ECS, or Cloud Run using 12-factor principles - 7 basic and 3 intermediate.
mkdir platform-api && cd platform-api
npm init -y
npm pkg set type=module
npm install express@5
npm install -D typescript@5.6For Kubernetes manifests and scaling, see Kubernetes Deployment and HPA & Resource Limits.
import { z } from "zod";
const envSchema = z.object({
PORT: z.coerce.number().default(3000),
NODE_ENV: z.enum(["development", "production", "test"]),
DATABASE_URL: z.string().url(),
});
export const env = envSchema.parse(process.env);import express from "express";
import { env } from "./env.js";
const app = express();
app.get("/health", (_req, res) => res.json({ status: "ok" }));
app.listen(env.PORT, "0.0.0.0");PORT; default 3000 for local only0.0.0.0 inside containersapp.use((req, res, next) => {
const start = Date.now();
res.on("finish", () => {
console.log(JSON.stringify({
method: req.method,
path: req.path,
status: res.statusCode,
ms: Date.now() - start,
}));
});
next();
});// Bad: in-memory session store at scale
const sessions = new Map<string, string>();
// Good: Redis or DB session store
import { getSession } from "./session-store.js";# Release phase (Job / initContainer)
npx prisma migrate deploy
# Run phase (Deployment CMD)
node dist/main.jsapp.get("/health", (_req, res) => res.json({ status: "ok" }));
app.get("/ready", async (_req, res) => {
const ok = await pingDatabase();
res.status(ok ? 200 : 503).json({ status: ok ? "ready" : "not_ready" });
});NODE_ENV=productionenv:
- name: NODE_ENV
value: productionENV aloneapiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: ghcr.io/acme/api:sha-abc123
ports:
- name: http
containerPort: 3000
envFrom:
- configMapRef:
name: api-config
- secretRef:
name: api-secrets
readinessProbe:
httpGet:
path: /ready
port: http
livenessProbe:
httpGet:
path: /health
port: httpSee Kubernetes Deployment for full manifest.
const server = app.listen(env.PORT, "0.0.0.0");
process.on("SIGTERM", () => {
server.close(() => process.exit(0));
});| Factor | Node implementation |
|---|---|
| Codebase | One git repo per service |
| Dependencies | package-lock.json + npm ci in image |
| Config | process.env + Zod |
| Backing services | Postgres, Redis as attached resources |
| Build, release, run | CI build image, CD deploy tag, CMD runs node |
| Processes | One container = one node process |
| Port binding | PORT env |
| Concurrency | Scale replicas via HPA |
| Disposability | Fast boot, SIGTERM drain |
| Dev/prod parity | Same Docker image locally and prod |
K8s: full control, multi-cloud. ECS: AWS-native, less ops than K8s. Cloud Run: simplest HTTP autoscaler. See ECS Fargate & Cloud Run.
Helm helps when you have many services and environments. Start with plain YAML or Kustomize for one API.
K8s Secrets, ECS task secrets, or external secret operators - ConfigMaps & Secrets.
Minimum 2 for HA. Set requests/limits from load tests - HPA & Resource Limits.
No. K8s is the process supervisor. PM2 is for VMs - PM2 & systemd.
Platform deploy runs images built per Docker Best Practices.
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