Docker Compose Patterns for Production-Ready Services
Battle-tested Docker Compose patterns for development, testing, and production deployments.
February 25, 2026 · 8 min · 1514 words · Rob Washington
Table of Contents
Docker Compose bridges the gap between single-container development and full orchestration. These patterns will help you build maintainable, production-ready configurations.
# services/app/Dockerfile# Base stageFROM node:20-alpine AS baseWORKDIR /appRUN apk add --no-cache tiniENTRYPOINT["/sbin/tini","--"]# Dependencies stageFROM base AS depsCOPY package*.json ./RUN npm ci --only=production &&\
cp -R node_modules /prod_modules &&\
npm ci# Development stageFROM base AS developmentCOPY --from=deps /app/node_modules ./node_modulesCOPY . .EXPOSE 3000 9229CMD["npm","run","dev"]# Build stageFROM base AS buildCOPY --from=deps /app/node_modules ./node_modulesCOPY . .RUN npm run build# Production stageFROM base AS productionENVNODE_ENV=production
COPY --from=deps /prod_modules ./node_modulesCOPY --from=build /app/dist ./distUSER nodeEXPOSE 3000CMD["node","dist/main.js"]
services:app:depends_on:db:condition:service_healthyredis:condition:service_healthymigrations:condition:service_completed_successfullymigrations:build:./services/appcommand:npm run migratedepends_on:db:condition:service_healthyrestart:"no"
services:api:networks:- frontend- backenddb:networks:- backend # Not exposed to frontendnginx:networks:- frontendports:- "80:80"networks:frontend:backend:internal:true# No external access
services:app:logging:driver:json-fileoptions:max-size:"10m"max-file:"5"labels:"app,environment"env:"NODE_ENV"# Or send to external serviceapp-prod:logging:driver:syslogoptions:syslog-address:"tcp://logs.example.com:514"tag:"myapp/{{.Name}}"
# Start in backgrounddocker compose up -d
# Rebuild and startdocker compose up -d --build
# View logsdocker compose logs -f app
# Execute command in running containerdocker compose exec app sh
# Run one-off commanddocker compose run --rm app npm run migrate
# Stop and removedocker compose down
# Stop, remove, and delete volumesdocker compose down -v
# Pull latest imagesdocker compose pull
# View running servicesdocker compose ps
# View resource usagedocker compose top
Good Compose configurations are layered: base settings that work everywhere, with targeted overrides for each environment. Keep the base minimal, let overrides handle specifics.
Start simple, add complexity only when needed. A working two-service setup beats an elaborate configuration that nobody understands.
📬 Get the Newsletter
Weekly insights on DevOps, automation, and CLI mastery. No spam, unsubscribe anytime.