Docker Compose is underused. Most tutorials show you how to run a database alongside your app — but Compose can handle your entire development workflow: hot reload, environment parity, secrets management, and multi-service orchestration.
The Development Stack
A complete Next.js + Postgres + Redis development environment:
# docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- '3000:3000'
volumes:
- .:/app
- /app/node_modules # exclude node_modules from mount
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 5s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
The Development Dockerfile
# Dockerfile.dev
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
# Don't copy source -- it's mounted as a volume
CMD ["npm", "run", "dev"]
The volume mount at .:/app means code changes on your host instantly reflect in the container. Hot reload works without rebuilding the image.
Production Dockerfile
# Dockerfile
FROM node:20-alpine AS base
# Dependencies
FROM base AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Build
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Runner
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
Multi-stage builds keep your production image lean. The runner stage has no build tools, no source code, no devDependencies.
Database Migrations on Start
Run Prisma migrations automatically when the container starts:
# In docker-compose.yml
app:
command: sh -c 'npx prisma migrate deploy && npm run dev'
Or use an entrypoint script for more control:
#!/bin/sh
# entrypoint.sh
echo 'Waiting for database...'
until npx prisma db push --skip-generate 2>&1; do
echo 'Database not ready, retrying in 2s...'
sleep 2
done
echo 'Database ready'
exec "$@"
Environment Management
Use .env.docker for container-specific overrides:
app:
env_file:
- .env # base config
- .env.docker # docker-specific overrides (localhost -> service names)
# .env.docker
DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp
REDIS_URL=redis://cache:6379
# Override localhost references with service names
Useful Commands
# Start everything
docker compose up
# Rebuild after package changes
docker compose up --build
# Run a migration
docker compose exec app npx prisma migrate dev
# Open a shell in the app container
docker compose exec app sh
# View logs for a specific service
docker compose logs -f app
# Reset the database
docker compose down -v && docker compose up
Production Compose Override
# docker-compose.prod.yml
services:
app:
build:
dockerfile: Dockerfile # production image
restart: unless-stopped
environment:
- NODE_ENV=production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
The Ship Fast Skill Pack at whoffagents.com includes a /deploy skill that generates production-ready Dockerfiles, Compose configs, and CI/CD pipeline configs for your stack. $49 one-time.
Top comments (1)
Great breakdown, this is a solid example of how Docker Compose can handle a full-stack workflow, from development to production, with proper isolation and scalability.
Managing multi-service stacks like Next.js + PostgreSQL + Redis can get complex, especially when scaling or deploying across environments. Using a reliable infrastructure helps a lot here.
Platforms like AccuWeb.Cloud make this easier with one-click Docker deployment and scalable VPS, so you can run your entire Compose stack smoothly without worrying about setup or performance bottlenecks. It’s a good option for developers looking to move from local dev to production-ready environments quickly