DEV Community

Alex Spinov
Alex Spinov

Posted on

The Docker Compose Template I Start Every Project With

I've written 50+ docker-compose files. This is what they all converge to.

Every new project starts with this template. It covers 90% of use cases.

version: '3.8'

services:
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/app
      - REDIS_URL=redis://cache:6379/0
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    volumes:
      - .:/app
    restart: unless-stopped
    healthcheck:
      test: curl -f http://localhost:8000/health || exit 1
      interval: 30s
      timeout: 10s
      retries: 3

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: pg_isready -U postgres
      interval: 5s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redisdata:/data

volumes:
  pgdata:
  redisdata:
Enter fullscreen mode Exit fullscreen mode

Why this template works

1. Health checks with depends_on conditions

The app waits for Postgres to be actually ready, not just running. This fixes the #1 Docker Compose issue: "app crashes because database isn't ready yet."

2. Alpine images

postgres:16-alpine is 80MB vs 400MB for the full image. Faster pulls, smaller containers.

3. Named volumes

Data persists between restarts. No more "where did my database go?"

4. unless-stopped restart policy

Containers restart on crash but not when you explicitly stop them. The right default.

5. Port mapping

All services accessible from your host for debugging. Remove port mappings in production.


The Dockerfile that goes with it

FROM python:3.12-slim

WORKDIR /app

# Install dependencies first (cached layer)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy app code
COPY . .

EXPOSE 8000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Enter fullscreen mode Exit fullscreen mode

Variations I use

+ Worker process:

  worker:
    build: .
    command: python -m celery -A tasks worker --loglevel=info
    depends_on:
      - cache
      - db
Enter fullscreen mode Exit fullscreen mode

+ Nginx reverse proxy:

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
Enter fullscreen mode Exit fullscreen mode

What's in YOUR docker-compose template? Any services I'm missing?


Follow me for more DevOps patterns. I maintain 77 containerized scrapers.


More from me: 10 Dev Tools I Use Daily | 77 Scrapers on a Schedule | 150+ Free APIs

Top comments (0)