Docker Best Practices
A condensed summary of the 25 most important Docker practices for Node.js teams - drawn from every page in this section.
Search across all documentation pages
A condensed summary of the 25 most important Docker practices for Node.js teams - drawn from every page in this section.
Multi-stage builds always: Build TypeScript in build; run node dist/main.js in prod - Multi-Stage Builds.
npm ci --omit=dev in runtime stage: Reproducible production dependency graph only.
Never npm install in Docker: Lockfile drift breaks prod parity.
Comprehensive .dockerignore: Exclude node_modules, tests, .git, .env - Image Slimming.
Default base node:24-bookworm-slim: glibc compatibility for native modules.
Evaluate Alpine only with CI matrix: musl breaks sharp, prisma, bcrypt - Distroless & Alpine Trade-offs.
Pin base image digests: FROM node:24-bookworm-slim@sha256:... prevents surprise rebuilds.
Run as non-root: USER node after chown -R node:node /app - Non-Root Containers.
Bind 0.0.0.0 and use PORT env: Required for K8s, ECS, Cloud Run.
One process per container: Separate API and worker images.
/health for liveness: No database calls; fast 200 - Health & Readiness Probes.
/ready for readiness: Check primary DB with short timeout.
Startup probe for slow boots: Migrations and cache warm before liveness.
Fail readiness on SIGTERM drain: Stop new traffic before shutdown - Graceful Shutdown.
No secrets in layers: Inject via orchestrator secrets at runtime.
No .env in COPY: Use .dockerignore and CI build args only for non-secret metadata.
Compile native modules inside Linux build stage: Never copy host node_modules.
Scan images in CI: Trivy, Grype, or ECR native scanning before deploy.
Tag images with git SHA: :main is not a deploy tag; use immutable SHA tags.
Deploy the same artifact tested in CI: Build once, promote digest - CI/CD Best Practices.
NODE_ENV=production in runtime: Enables production code paths in frameworks.
Log to stdout/stderr: No file logging inside containers.
Set resource requests from load tests: Memory limit should exceed RSS under p99 load - HPA & Resource Limits.
Document local docker compose parity: Same env var names as K8s manifests.
Review image size quarterly: docker history and dependency audit when size grows 2x.
Multi-stage build with npm ci --omit=dev in the final stage. It cuts size, attack surface, and dev-tool leakage in one change.
After bookworm-slim multi-stage works reliably. Distroless is a security hardening step, not day-one requirement.
Weekly automated Renovate PRs for digest bumps, plus immediate rebuild on critical Node security advisories.
Yes. Kubernetes runs containers; someone must build and scan the image. CI does the build; developers debug locally.
DevDependencies in build stage only. Never ship typescript or @types/* to production unless you have a documented reason.
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