Developer Guide

Intermediate30–45 min

Deploy NestJS with Docker Compose

Package a NestJS service as a small production image and operate it with Docker Compose, health checks, logs, and controlled updates.

1

Create a multi-stage image

Build dependencies separately and run the compiled application as a non-root user.

FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build --chown=node:node /app/node_modules ./node_modules
COPY --from=build --chown=node:node /app/dist ./dist
USER node
CMD ["node", "dist/main.js"]
2

Define the service

Bind the API to loopback when a reverse proxy is on the same host and include a health check.

services:
  api:
    build: .
    restart: unless-stopped
    env_file: .env.production
    ports:
      - "127.0.0.1:<port>:<port>"
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:<port>/health"]
      interval: 30s
      timeout: 5s
      retries: 3

Important: Never commit .env.production or bake secrets into the image.

3

Build and start

Validate the resolved Compose model, then build and launch in the background.

docker compose config
docker compose up -d --build
4

Inspect health and logs

Confirm the container is healthy and watch startup output for configuration errors.

docker compose ps
docker compose logs --tail=100 -f api
5

Deploy an update

Pull code or the pinned image, rebuild only what changed, and remove obsolete containers.

Commandwarning
docker compose pull
docker compose up -d --build --remove-orphans

Final verification

  • ✓ docker compose config reports no errors
  • ✓ docker compose ps reports a healthy API
  • ✓ The health endpoint responds through the reverse proxy
  • ✓ No secret file is tracked by Git