“Connection refused” errors? The app starts before the database is ready. Here’s the fix.
What doesn’t work
This only waits for the container to start, not for it to be ready:
services:
app:
depends_on:
- db # Container starts, but database isn't ready yet
What actually works
Add health checks:
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
app:
image: myapp
depends_on:
db:
condition: service_healthy # Now it actually waits for the database
Common health checks
PostgreSQL:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
MySQL:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
Redis:
healthcheck:
test: ["CMD", "redis-cli", "ping"]
HTTP Service:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
# Or wget if curl isn't available
test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://localhost:8080/health || exit 1"]
What the options mean
interval: How often to run the checktimeout: How long to wait for a responseretries: Failures before marking unhealthystart_period: Grace period for slow services
Multiple dependencies
services:
app:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started # Mix different conditions
migration:
condition: service_completed_successfully # Waits for migrations to finish
Development tip
Add restart logic for local dev:
services:
app:
depends_on:
db:
condition: service_healthy
restart: true # Restarts app when db restarts
The app will reconnect when the database restarts.
Debugging
# Check health status
docker compose ps
# See health check output
docker inspect --format='{{json .State.Health}}' <container_name> | jq