A healthcheck is a command Docker 514 runs inside the container on a schedule; exit code 0 means healthy. The API's image has one (Planning Images), and a healthcheck: key adds one to an image that lacks it, such as postgres:18, whose pg_isready exists for this purpose:
services:
api:
# ...build, ports and environment as before...
depends_on:
db:
condition: service_healthy
restart: true
db:
# ...image, environment, ports and volumes as before...
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 3s
retries: 5
start_period: 30s
start_interval: 1sCMD-SHELL runs the test through /bin/sh; $$ keeps Compose 514 from interpolating the container's variables. Five failures in a row mark the container unhealthy, failures during start_period do not count, and start_interval (Compose 2.20.2, Engine 25) probes every second until the first success. -h 127.0.0.1 matters: a first start initializes the database with a temporary server on a Unix socket only, which a socket-based check would call ready just before it shuts down. Start from an empty volume:
docker compose down -v >/dev/null 2>&1
docker compose up -d 2>&1 | grep -E 'db-1 (Started|Healthy)|api-1 Started'
docker inspect l3-booknest-api-1 --format 'restarts: {{.RestartCount}}'
docker compose logs --no-log-prefix db | grep -E 'accept conn|shut down$|init process' \
| sed -E 's/^[0-9-]+ ([0-9:.]+) UTC (\[[0-9]+\]) LOG: +/\1 \2 /'Container l3-booknest-db-1 Started Container l3-booknest-db-1 Healthy Container l3-booknest-api-1 Started restarts: 0 11:04:15.616 [60] database system is ready to accept connections 11:04:16.050 [60] database system is shut down PostgreSQL init process complete; ready for start up. 11:04:16.136 [1] database system is ready to accept connections
The API started only once db was healthy and never restarted. The log shows the temporary server ready and shut down before the real one, PID 1 in the container, started.

Keep healthchecks cheap and local: a check that calls another service turns one outage into two.