Docker for Development: A No-Nonsense Setup
Docker for Development: A No-Nonsense Setup
Docker in production is well-understood. Docker in development? That's where things get messy. Here's a setup that actually works.
The Problem
Most Docker dev setups suffer from:
- Slow file syncing — changes take seconds to reflect
- No debugger — you can't attach VS Code's debugger
- Dependency hell — node_modules on Linux vs Mac volumes
The Solution: Docker Compose + Bind Mounts
yaml
# docker-compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules # Anonymous volume for node_modules
environment:
- DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
depends_on:
- db
db:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:The Dev Dockerfile
dockerfile
# Dockerfile.dev
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]Key Tricks
1. Anonymous Volume for node_modules
The line /app/node_modules creates an anonymous volume that prevents your host's node_modules from overwriting the container's. This solves the Linux/Mac binary incompatibility issue.
2. Database Persistence
The named volume pgdata ensures your database survives container restarts.
3. Hot Reloading
Bind mounting your project directory (.:/app) means file changes are instantly visible in the container. Next.js, Vite, and similar tools will hot-reload automatically.
Common Commands
bash
# Start everything
docker compose up -d
# View logs
docker compose logs -f app
# Run a one-off command
docker compose exec app npx prisma migrate dev
# Tear it all down (keep data)
docker compose down
# Nuclear option (destroy data too)
docker compose down -vThis setup gives you the isolation benefits of Docker without sacrificing the development experience.
Explore by topic