# Development (auto-loads override)
docker compose up
# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Networking
Service Discovery
Services in the same Compose network resolve by service name:
# From "app" container:
postgres://postgres:postgres@db:5432/app_dev # "db" resolves to the db container
redis://redis:6379/0 # "redis" resolves to the redis container
Custom Networks
services:frontend:networks:-frontend-netapi:networks:-frontend-net-backend-netdb:networks:-backend-net# Only reachable from api, not frontendnetworks:frontend-net:backend-net:
Exposing Only What's Needed
services:db:ports:-"127.0.0.1:5432:5432"# Only accessible from host, not network# Omit ports entirely in production -- accessible only within Docker network
Volume Strategies
volumes:# Named volume: persists across container restarts, managed by Dockerpgdata:# Bind mount: maps host directory into container (for development)# - ./src:/app/src# Anonymous volume: preserves container-generated content from bind mount override# - /app/node_modules
Common Patterns
services:app:volumes:-.:/app# Source code (bind mount for hot reload)-/app/node_modules# Protect container's node_modules from host-/app/.next# Protect build cachedb:volumes:-pgdata:/var/lib/postgresql/data# Persistent data-./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql# Init scripts
Container Security
Dockerfile Hardening
# 1. Use specific tags (never :latest)
FROM node:22.12-alpine3.20
# 2. Run as non-root
RUN addgroup -g 1001 -S app && adduser -S app -u 1001
USER app
# 3. Drop capabilities (in compose)
# 4. Read-only root filesystem where possible
# 5. No secrets in image layers
Compose Security
services:app:security_opt:-no-new-privileges:trueread_only:truetmpfs:-/tmp-/app/.cachecap_drop:-ALLcap_add:-NET_BIND_SERVICE# Only if binding to ports < 1024
Secret Management
# GOOD: Use environment variables (injected at runtime)services:app:env_file:-.env# Never commit .env to gitenvironment:-API_KEY# Inherits from host environment# GOOD: Docker secrets (Swarm mode)secrets:db_password:file:./secrets/db_password.txtservices:db:secrets:-db_password# BAD: Hardcoded in image# ENV API_KEY=sk-proj-xxxxx # NEVER DO THIS
# BAD: Using docker compose in production without orchestration
# Use Kubernetes, ECS, or Docker Swarm for production multi-container workloads
# BAD: Storing data in containers without volumes
# Containers are ephemeral -- all data lost on restart without volumes
# BAD: Running as root
# Always create and use a non-root user
# BAD: Using :latest tag
# Pin to specific versions for reproducible builds
# BAD: One giant container with all services
# Separate concerns: one process per container
# BAD: Putting secrets in docker-compose.yml
# Use .env files (gitignored) or Docker secrets