Skip to content
DevPlainly

Docker Compose Generator

Pick your app and the databases it needs. You get a compose.yaml with sensible defaults and a .env.example for the passwords, ready to run with one command.

Databases and services
services:
  app:
    build: .
    ports:
      - "3000:3000"
    env_file: .env
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
    # start the app only when every database answers its health check
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

# named volumes keep the data when containers are recreated
volumes:
  postgres-data:

Copy .env.example to .env, change the passwords, then run docker compose up -d.

What's in the generated compose.yaml

  • Passwords in .env, not in the file. The compose file uses ${POSTGRES_PASSWORD}-style variables, so you can commit it safely and keep the real values in an ignored .env.
  • Named volumes for every database, so your data survives docker compose down and container upgrades.
  • Health checks and startup order. The app waits until each database actually answers, not just until its container starts, which avoids "connection refused" errors on the first boot.
  • Connection URLs such as DATABASE_URL and REDIS_URL, built from the same variables, so your app and the database never disagree about a password.
  • restart: unless-stopped, so services come back after a crash or a reboot.
  • Databases stay private by default. Only the app is published. If you expose database ports for local tools, they're bound to 127.0.0.1 so they aren't reachable from the internet.

Run it

cp .env.example .env   # then change every password
docker compose up -d
docker compose ps        # every service should say "healthy"
docker compose logs -f app

Inside the network, services use their names

Containers in the same compose file reach each other by service name: your app connects to postgres:5432, not localhost:5432. localhost inside a container means the container itself, which is the most common reason a first compose setup can't reach its database.

Why there's no version: line

The top-level version field is obsolete in the current Compose specification, and Docker Compose v2 ignores it and prints a warning. The modern file name is compose.yaml, although docker-compose.yml still works.

Keep learning