Dockerization

Dockerize Node.js: Ship APIs That Actually Behave in Containers

Node.js is deceptively simple to containerize — until you hit PID 1 signal problems, zombie processes, and 1.2 GB images running as root. We build Node.js containers that handle SIGTERM gracefully, run as non-root, and weigh under 150 MB with all dependencies included.

Need this done for your project?

We implement, you ship. Async, documented, done in days.

Start a Brief

Why Dockerize Node.js

Node.js servers need consistent runtime versions, native module compilation, and proper signal handling. Without Docker, you end up with nvm version mismatches, different OpenSSL builds between staging and production, and deployments that ignore SIGTERM because Node was not running as PID 1.

Containerizing Node also enables horizontal scaling — spin up identical replicas behind a load balancer without worrying about shared filesystem state or port conflicts.

Our Docker Implementation for Node.js

We use a multi-stage Dockerfile with node:20-alpine as the base:

  • Stage 1 — install: Copies package.json and package-lock.json, runs npm ci --omit=dev for production deps only. Native modules that need build tools use a separate build-base install.
  • Stage 2 — runner: Copies app source and production node_modules. Creates a node user with addgroup/adduser, sets USER node. Uses dumb-init or tini as the entrypoint to handle PID 1 reaping.

The Compose file defines health checks using wget --spider http://localhost:3000/health, sets stop_grace_period: 30s, and passes secrets via env_file. We configure logging with json-file driver and size rotation.

What You Get

  • Multi-stage Dockerfile with non-root user and init process
  • Graceful shutdown handler wired to SIGTERM and SIGINT
  • docker-compose.yml with health checks, logging config, and restart policy
  • .dockerignore excluding tests, docs, and dev configs
  • CI/CD build step with layer caching for node_modules

Best Practices We Follow

No root: Every container runs as a non-root user — USER node is set after copying files with correct ownership.

Signal handling: tini as PID 1 ensures SIGTERM reaches your Node process. We also add a graceful shutdown hook that drains HTTP connections before exiting.

Layer caching: package*.json files are copied and installed before source code, so dependency layers are only rebuilt when the lockfile changes.

No secrets in layers: Environment variables are injected at runtime, never baked in with ENV or ARG.

Why Anubiz Engineering

100% async — no calls, no meetings
Delivered in days, not weeks
Full documentation included
Production-grade from day one
Security-first approach
Post-delivery support included

Ready to get started?

Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.