Every developer has lost hours to "works on my machine" problems. Different Node versions, missing system dependencies, conflicting database versions. Docker solves this — but only if your setup doesn't make development painfully slow.
The Development Docker Compose
Our standard development stack uses Docker Compose with these principles:
- App code runs on host, services run in Docker — Your editor, TypeScript LSP, and hot reload work natively. Postgres, Redis, and other services run in containers.
- Volume mounts for data persistence — Database data survives container restarts
- Environment variable management —
.env.examplechecked in,.env.localgitignored
Service Configuration
A typical web app needs:
services:
postgres:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
environment:
POSTGRES_DB: app_dev
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
mailhog:
image: mailhog/mailhog
ports:
- "8025:8025" # Web UI
- "1025:1025" # SMTP
Multi-Stage Production Builds
Development and production images should share a base but differ in their final stage. Use multi-stage builds:
- Stage 1 (deps): Install all dependencies including devDependencies
- Stage 2 (build): Compile TypeScript, build Next.js
- Stage 3 (production): Copy only production artifacts, install only production deps. Final image is 80% smaller.
Developer Experience Tips
- Add a
Makefilewith commands likemake dev,make test,make seed - Use
docker compose watch(Compose v2.22+) for automatic sync and rebuild - Health checks on every service so
depends_onactually waits for readiness - Include a
scripts/setup.shthat gets a new developer from zero to running in one command
Want a Docker setup that your entire team will actually enjoy using? We build developer-friendly infrastructure.