Docker and Compose
Why Docker Compose depends_on does not always mean ready
Use Compose dependency conditions and application retries to avoid web containers racing their databases.
By AppLaunch Editorial · Reviewed 2026-08-25
Direct answer
Basic dependency order controls creation order, not application readiness. Add a real dependency health check and use condition: service_healthy when appropriate, then retain retry logic because dependencies can fail again after startup.
What this means in plain English
depends_on tells Compose which container to start first, but “started” can mean only that its process was launched. A database may still be preparing files, and a web app may try to connect too soon. That is why a cold start can fail even though the order looks correct.
Add a real health check to the dependency and wait for service_healthy where it fits. The application should still retry temporary failures, because startup ordering helps only at the beginning and does not protect against a later restart or short network problem.
How do you wait for a dependency correctly?
| Creation | Container has been started |
|---|---|
| Healthy | Configured health command passes |
| Resilient | Consumer reconnects after later failure |
A simple example
Compose starts MySQL, then immediately starts PHP. PHP makes its first query before MySQL is ready and exits. A fixed ten-second sleep sometimes works but fails on a slower machine. A database health check waits for a real connection, while PHP retry logic handles later interruptions.
What to do, step by step
1. Reproduce the cold-start race.
Start here before buying anything or changing several settings at once. It gives you a clear starting point based on creation: container has been started. Write the result down so you can compare it later.
2. Add a database-aware health check.
Use the same files, versions and settings that the real project will use. A quick test with an empty or different setup can look successful while completely missing the problem you are trying to solve.
3. Gate the dependent service on service_healthy.
Try the busiest realistic situation, not the easiest one. Include the people, data, traffic or background work you genuinely expect, then watch for slowdowns and errors rather than relying on a single headline number.
4. Test dependency restart after the stack is live.
Finish by checking the result against resilient: consumer reconnects after later failure. Keep the old setting or release available until you know the change works and can be reversed safely.
One more useful tip
Avoid guessing with longer sleep commands. They make fast starts unnecessarily slow and still fail when the dependency takes even longer than expected.
Common mistakes and how to avoid them
Adding fixed sleep delays.
This gives a misleading or unsafe result because it leaves out creation. A better approach is to reproduce the cold-start race, then check the result before making the change permanent.
Checking the wrong database or credentials.
This gives a misleading or unsafe result because it leaves out healthy. A better approach is to add a database-aware health check, then check the result before making the change permanent.
Assuming startup ordering provides runtime resilience.
This gives a misleading or unsafe result because it leaves out resilient. A better approach is to gate the dependent service on service_healthy, then check the result before making the change permanent.
Words explained
- container
- A packaged, isolated way to run an application with the files and software it needs.
- Compose
- Docker Compose is a file-based way to describe several containers, their settings, storage and networks as one application.
- health check
- A small test that tells Docker whether the application inside a container is actually working.
Quick checklist
- Reproduce the cold-start race.
- Add a database-aware health check.
- Gate the dependent service on service_healthy.
- Test dependency restart after the stack is live.
Common questions
What is the simple answer?
Basic dependency order controls creation order, not application readiness. Add a real dependency health check and use condition: service_healthy when appropriate, then retain retry logic because dependencies can fail again after startup.
What should I check first?
Start with creation: container has been started. That is usually more useful than choosing from a marketing label or copying somebody else’s setting.
How can I make the change safely?
Reproduce the cold-start race. Then change one thing at a time, keep a backup or old version, and use the same real-world test after each change.
What is the easiest mistake to avoid?
Adding fixed sleep delays. Avoiding that one mistake makes the rest of the comparison much more trustworthy.