Recipes

One thing per recipe. Read them in order for a full picture, or jump to the one you need. All of them are applied together in the full example.

  1. Build - From source to an image that is safe to ship.
  2. Run node directly, not npm start - Make node PID 1 so Kubernetes signals reach your application code.
  3. Container images for Node.js - What a production image should contain, and the recipes that get you there for plain Node.js, Bun, Next.js and TanStack Start.
  4. A minimal multi-stage Dockerfile - Install with npm ci, build in one stage, copy only what runs into the final image.
  5. Distroless instead of Alpine or Debian slim - Ship the Node.js runtime and your app, nothing else. No shell, no package manager, non-root.
  6. Private packages with Docker build secrets - Pass NPM_TOKEN as a BuildKit secret. Never put it in an ARG, an ENV, or a copied .npmrc.
  7. Build an image with Cloud Native Buildpacks - Get a production Node.js image without writing a Dockerfile, using pack and Paketo.
  8. Containerize a Hono API - A Hono service on the Node.js adapter, built in two stages into a distroless image, with the Bun variant alongside.
  9. Containerize a Next.js app - Build with output standalone, copy three folders into a distroless image, run server.js directly.
  10. Containerize a TanStack Start app with Nitro - Add the Nitro Vite plugin, build a node-server bundle into .output, and run the entry with node in a distroless image.
  11. Run - From an image to Pods that start, stop and route traffic correctly.
  12. Kubernetes manifests for a Node.js app - The plain YAML baseline: a Deployment and a Service with probes, resources, security context and a named port. Kustomize and Helm build on it.
  13. Kustomize base and overlays - One base with the manifests, one overlay per environment that changes only the image tag, replicas and config.
  14. A minimal Helm chart - A chart with one Deployment, one Service, a PDB and a values file with only the knobs you actually turn.
  15. Configuration from the environment - Build one image, promote it through environments, and read every setting from env vars.
  16. Kubernetes probes done right - Liveness restarts, readiness routes. Give them different endpoints, keep dependencies out, and use readiness to shed load.
  17. Graceful shutdown on SIGTERM - Stop accepting connections, finish in-flight requests, then exit with a deadline.
  18. Graceful shutdown with Express - app.listen() returns a plain Node.js http.Server. Close that, not the app.
  19. Graceful shutdown with Fastify - Use app.close() with forceCloseConnections and onClose hooks, and listen on 0.0.0.0.
  20. Graceful shutdown with Hono - Hono is runtime-agnostic. Close the server the adapter gave you, on Node or on Bun.
  21. Graceful shutdown with Elysia - Elysia runs on Bun. Call app.stop() on SIGTERM and ship it in the Bun distroless image.
  22. Graceful shutdown with NestJS - Turn on enableShutdownHooks() and use the lifecycle hooks to flip readiness and close resources in order.
  23. Graceful shutdown with Next.js - The standalone server already handles SIGTERM. Add readiness and cleanup around it, do not replace it.
  24. Graceful shutdown with TanStack Start and Nitro - Nitro's node server drains in-flight requests on SIGTERM. Tune its timeout and add readiness in the server entry.
  25. Pod, Service, Ingress, Gateway API and NetworkPolicy - How a request reaches your container, and why you should say who may talk to it.
  26. Zero-downtime rolling updates - Rolling update strategy, a PodDisruptionBudget and spread across nodes so a deploy never drops requests.
  27. Measure and right-size - See what the app does, then set the numbers.
  28. Log JSON lines to stdout - One JSON object per line on stdout. No files, no log rotation, no agents inside the container.
  29. Telemetry with OpenTelemetry - Kubernetes collects nothing about your app. Export logs, metrics and traces yourself, in one standard.
  30. Memory and CPU for Node.js Pods - Measure before you set numbers. Then give Node.js a full CPU or two, size the heap under the memory limit, and re-measure after every runtime upgrade.