DevDocs
🐳 Docker⭐ Featured

Docker Compose Production Guide

Master Docker Compose for multi-container applications — from local dev to production-grade deployments with health checks, networking, and secrets.

Satveek Gupta February 1, 2026 15 min read Updated May 15, 2026
docker compose containers production networking
Edit this page on GitHub

Overview

Docker Compose transforms complex multi-container setups into a single declarative YAML file. This guide covers everything from basic local development to production-hardened deployments.

Architecture

Loading diagram…

Basic Compose File

docker-compose.yml
version: '3.9'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      target: production
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=${DATABASE_URL}
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    restart: unless-stopped
    networks:
      - app-network

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    networks:
      - app-network

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/ssl/certs:ro
    depends_on:
      - app
    networks:
      - app-network

volumes:
  postgres_data:
  redis_data:

networks:
  app-network:
    driver: bridge

Multi-Stage Dockerfile

Dockerfile
# ---- Base ----
FROM node:22-alpine AS base
WORKDIR /app
COPY package*.json ./

# ---- Dependencies ----
FROM base AS deps
RUN npm ci --only=production

# ---- Build ----
FROM base AS builder
RUN npm ci
COPY . .
RUN npm run build

# ---- Production ----
FROM node:22-alpine AS production
WORKDIR /app
ENV NODE_ENV=production

COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json .

RUN addgroup -g 1001 nodejs && \
    adduser -S nextjs -u 1001 && \
    chown -R nextjs:nodejs /app

USER nextjs

EXPOSE 3000
CMD ["node", "dist/index.js"]
Note

Multi-stage builds drastically reduce image size. A typical Node.js app goes from ~1.2GB to ~150MB.

Environment Management

.env.dev
NODE_ENV=development
DATABASE_URL=postgresql://postgres:dev@localhost:5432/mydb
REDIS_PASSWORD=devpass
POSTGRES_DB=mydb
POSTGRES_USER=postgres
POSTGRES_PASSWORD=dev

Common Commands

compose-commands.sh
# Start all services in background
docker compose up -d

# Start specific service
docker compose up -d app

# View logs
docker compose logs -f app

# Scale a service
docker compose up -d --scale app=3

# Execute command in container
docker compose exec app sh

# Rebuild without cache
docker compose build --no-cache

# Stop and remove volumes
docker compose down -v

# Pull latest images
docker compose pull

Health Checks

healthcheck.yml
services:
  app:
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
Tip

Always add health checks before depends_on. Without them, Compose only waits for the container to start, not for the service to be ready.

Secrets Management

docker-compose.secrets.yml
services:
  app:
    secrets:
      - db_password
      - api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    external: true  # Managed by Docker Swarm / external secret store

Troubleshooting

ProblemCommand
Container keeps restartingdocker compose logs <service>
Port already in uselsof -ti:3000 | xargs kill
Volume permissionsdocker compose exec app chown -R app:app /data
Network conflictsdocker network prune
Out of disk spacedocker system prune -a

References

PreviousKubernetes Deployment StrategiesNextAWS EC2 Complete Setup Guide