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.
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 downand 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_URLandREDIS_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.1so 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 appInside 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
- Docker Compose for beginners: every line of a compose file explained.
- Dockerfile generator: create the Dockerfile your app service builds from.
- Backing up Docker volumes and securing a new VPS before you put it online.