What this error means
You used depends_on with condition: service_healthy, but the dependency service has no healthcheck. Docker Compose can only wait for a service to become "healthy" if that service defines a healthcheck. Without it, Compose raises:
- depends_on contains condition: service_healthy but no healthcheck defined
Fix it by adding a healthcheck to the dependency, or by using a different condition.
Minimal working example (MWE)
The example below starts an API only after Postgres reports healthy.
dervices:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: example
POSTGRES_USER: postgres
POSTGRES_DB: app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d app"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
api:
image: alpine:3.20
depends_on:
db:
condition: service_healthy
command: ["sh", "-c", "echo DB healthy; sleep 5"]
- db declares a healthcheck using pg_isready.
- api waits until db is healthy before it starts.
Run it:
docker compose up --wait
--wait makes compose block until services are “running/healthy”.
Quickstart
- Identify the dependency referenced with service_healthy.
- Example: web depends_on: db: { condition: service_healthy }
- Add a healthcheck to that dependency service.
- Use a fast, reliable command that proves readiness (not just that the port is open).
- Tune healthcheck timings.
- Use start_period to give the service time to warm up before counting retries.
- Validate the file.
- docker compose config
- Start the stack.
- docker compose up -d
- Verify health.
- docker compose ps
When to use which condition
| condition | What it waits for | Needs healthcheck |
|---|---|---|
| service_started | Container created and started | No |
| service_healthy | Healthcheck status is healthy | Yes |
| service_completed_successfully | One-shot container exited 0 | No |
If you cannot define a healthcheck, use service_started or a custom wait script.
Adding useful healthchecks
- Databases (Postgres):
healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d app"] interval: 5s timeout: 3s retries: 5 start_period: 10s - HTTP apps:
Ensure wget or curl exists in the image, or use a minimal script baked into the image.healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health || exit 1"] interval: 5s timeout: 2s retries: 10 start_period: 15s
Common pitfalls
- Missing healthcheck on the dependency: service_healthy only works if the dependency defines a healthcheck.
- Wrong service targeted: Verify the service name under depends_on matches the service with healthcheck.
- Indentation errors: healthcheck must be under the service, not top-level.
- Flaky healthcheck commands: Avoid commands that rely on external DNS or network; prefer local checks.
- Start-up grace period: Without start_period, the first few checks may fail before the service is actually ready.
- Wrong binary in image: If you use curl/wget/pg_isready, ensure it exists in the image.
- Swarm mode: docker stack deploy ignores depends_on; use alternative orchestration logic for Swarm.
Performance notes
- Keep interval reasonable (e.g., 5–30s). Very frequent healthchecks across many services add CPU overhead.
- Use simple commands. Each healthcheck spawns a process; heavier checks slow hosts.
- Increase start_period for services that need warm-up (databases, JVMs) to reduce retries and log noise.
- In development, consider longer intervals or fewer retries to speed up compose up.
Alternative fixes
Switch to service_started:
depends_on: db: condition: service_startedUse this when the application can tolerate connecting retries on its own.
App-level retry logic: Implement connection retries in the app (e.g., exponential backoff) so it can handle restarts of dependencies.
External wait tools: As a last resort, a tiny entrypoint script can poll the dependency (e.g., nc/wait-for) before starting the app.
Debugging checklist
- docker compose config to validate the YAML.
- docker compose ps to see health state (starting, healthy, unhealthy).
- docker logs <service> to inspect healthcheck failures.
- docker inspect --format '{{json .State.Health}}' <container> for detailed status and log output.
FAQ
Do I need a healthcheck on every service? No. Only services referenced with condition: service_healthy require it.
Why does service_started not wait for readiness? It only waits for the container process to start, not for the app to be ready.
Is depends_on honored in Swarm? Not for ordering; Swarm ignores depends_on. Use init jobs, orchestrator features, or app-level retries instead.
Can healthchecks restart unhealthy containers? Healthchecks mark containers unhealthy. Combine with restart policies if you want automatic restarts.
What if the error persists? Confirm the dependency actually defines healthcheck, names match, and your Compose CLI supports depends_on conditions (use the docker compose V2 plugin).