Skip to content

22 Deployment Docker

DodaTech 4 min read

title: Docker Deployment for Node.js REST APIs weight: 32 date: 2026-06-28 lastmod: 2026-06-28 description: Deploy Node.js REST APIs with Docker including multi-stage builds, Docker Compose for local development, production optimization, and CI/CD pipeline integration. tags: [api-development, nodejs]


Docker deployment for Node.js REST APIs containerizes the application with multi-stage builds for optimized images, Docker Compose for multi-service environments (app, database, Redis), and production-ready configuration.

```mermaid
flowchart TD
  A[Node.js App] --> B[Dockerfile]
  B --> C[Docker Image]
  C --> D[Container]
  D --> E[Production]
  B --> F[Multi-stage Build]
  F --> G[Stage 1: Install deps]
  F --> H[Stage 2: Build]
  F --> I[Stage 3: Production]
  style A fill:#e1f5fe
  style B fill:#c8e6c9
  style F fill:#fff9c4

Multi-stage builds separate dependency installation, building, and production runtime. The final image contains only production dependencies and the compiled code. Docker Compose orchestrates your API server, database, Redis, and other services.

Think of Docker like a shipping container for your application. The container has everything the app needs to run (Node.js, dependencies, config). It works the same on a developer's laptop, a test server, or a production cluster.

Example: Multi-Stage Dockerfile

# Stage 1: Install dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production

# Stage 2: Build stage
FROM node:20-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nodeuser

COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY --from=build /app/package.json ./

USER nodeuser

EXPOSE 3000

ENV NODE_ENV=production
ENV PORT=3000

CMD ["node", "dist/app.js"]

Example: Docker Compose for Development

version: '3.8'
services:
  app:
    build:
      context: .
      target: deps
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - DATABASE_URL=mongodb://mongo:27017/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - mongo
      - redis
    command: npx nodemon src/app.js

  mongo:
    image: mongo:7
    volumes:
      - mongo_data:/data/db
    ports:
      - "27017:27017"

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    ports:
      - "6379:6379"

volumes:
  mongo_data:
  redis_data:

Example: Production Docker Compose

version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=mongodb://mongo:27017/myapp
      - REDIS_URL=redis://redis:6379
      - JWT_SECRET=${JWT_SECRET}
    depends_on:
      - mongo
      - redis
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app

  mongo:
    image: mongo:7
    volumes:
      - mongo_data:/data/db
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    restart: unless-stopped

volumes:
  mongo_data:
  redis_data:

Common Mistakes

  1. Running Node.js as root in containers — Containers running as root are a security risk. Create a non-root user in the Dockerfile.
  2. Installing devDependencies in production images — Production images should only contain production dependencies. Use npm ci --only=production.
  3. Binding to 0.0.0.0 instead of localhost — Express defaults to localhost. In Docker, bind to 0.0.0.0 so the container accepts external connections.
  4. Not using .dockerignore — Without .dockerignore, node_modules, .env, and logs are copied into the build context, slowing builds and increasing image size.
  5. Hard-coding environment variables in Dockerfile — Use ARG for build-time variables and ENV for runtime defaults. Never hard-code secrets.

Practice Questions

  1. What is the benefit of multi-stage Docker builds?
  2. Why should you use a non-root user in containers?
  3. What is the purpose of volumes in Docker Compose?
  4. How do you handle health checks for Docker containers?
  5. Challenge: Create a complete Docker deployment for a Node.js REST API with MongoDB and Redis. Include: multi-stage Dockerfile, development docker-compose with hot reload, production docker-compose with Nginx reverse proxy, health checks, and non-root user. Test the deployment locally.

FAQ

What base image should I use for Node.js?

node:20-alpine is the most common. Alpine is small (~5MB) and secure. Avoid full images like node:20 for production.

How do I handle database migrations in Docker?

Run a separate init container or an entrypoint script that runs migrations before starting the app. Use depends_on with condition: service_healthy.

Should I use Docker for development?

Yes, Docker Compose provides reproducible development environments. Mount your source code as a volume and use nodemon for hot reload.

How do I debug a Node.js app running in Docker?

Use docker logs to view logs. Run docker exec -it container_name sh to shell into the container. Use Node.js inspector with --inspect=0.0.0.0.

What is the difference between CMD and ENTRYPOINT?

CMD provides default arguments for ENTRYPOINT. Use ENTRYPOINT for the main command and CMD for default arguments. CMD is easier to override at runtime.

Mini Project

Create a complete Docker deployment pipeline for a Node.js REST API. Include: multi-stage Dockerfile (deps, build, production), Docker Compose for development (app, mongo, redis), Docker Compose for production (app, nginx, mongo, redis), health checks, non-root user, .dockerignore, and a CI/CD script that builds and pushes the image.

What's Next

Now learn about environment configuration in Building REST APIs with Node.js.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro