Docker Compose: How to Wait for Container X Before Starting Container Y

In Docker Compose, services often depend on each other—for example, a web app may rely on a database. But while you can define service dependencies using the depends_on keyword, Docker Compose does not wait for one container to be “ready” before starting the next.

In this post, we’ll explore how to properly wait for container X to be ready before starting container Y in Docker Compose, especially in the context of databases and APIs.


🧠 The Problem: Startup Race Conditions

Let’s say you have two services:

services:
  db:
    image: postgres
  web:
    image: my-web-app
    depends_on:
      - db

Here, Docker Compose will:

  • Start db
  • Then start web

But it doesn’t guarantee that the database is ready to accept connections—only that the container has started. This can cause the web container to fail on startup if it tries to connect to the database too soon.


✅ Solution: Use a Wait-for Script or Tool

To solve this, you can use a wait-for-it or similar script in your dependent service to wait for the other container to be ready.


🔹 Option 1: Use wait-for-it.sh (Most Common)

wait-for-it is a popular shell script to pause execution until a service is ready.

📥 Step 1: Download the script

Download it and place it in your project directory (e.g., under scripts/wait-for-it.sh) and make it executable:

chmod +x scripts/wait-for-it.sh

🛠️ Step 2: Update Docker Compose service

services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: example

  web:
    image: my-web-app
    depends_on:
      - db
    entrypoint: ["./scripts/wait-for-it.sh", "db:5432", "--", "npm", "start"]
    volumes:
      - ./scripts:/scripts
  • entrypoint runs wait-for-it.sh and then starts your app.
  • "db:5432" tells it to wait for the db container on port 5432.

🔹 Option 2: Use dockerize

dockerize is a binary utility that can wait for TCP services before launching.

Example:

In your Dockerfile:

ADD https://github.com/jwilder/dockerize/releases/download/v0.6.1/dockerize-linux-amd64-v0.6.1.tar.gz /tmp/
RUN tar -C /usr/local/bin -xzvf /tmp/dockerize-linux-amd64-v0.6.1.tar.gz

In your docker-compose.yml:

entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-timeout", "60s", "npm", "start"]

🔹 Option 3: Use Custom Wait Script

You can also write your own bash script that loops until the service is ready:

#!/bin/bash
until pg_isready -h db -p 5432; do
  echo "Waiting for db..."
  sleep 2
done

npm start

Add this script in your image or mount it as a volume and run it as the entrypoint or command.


🔁 Using depends_on Correctly

Although depends_on doesn’t wait for readiness, it still helps control startup order. Combine it with a wait script for best results.

depends_on:
  - db

🧪 Testing It Works

You can simulate a slow-starting DB by adding a delay:

  db:
    image: postgres
    command: ["postgres", "-c", "shared_buffers=256MB"]

And see that your app properly waits using the script logs.


📝 Summary

MethodWaits for Service?Requires External Script?
depends_on❌ No (only starts in order)
wait-for-it.sh✅ Yes
dockerize✅ Yes
Custom script✅ Yes

✅ Best Practice

Use depends_on to define service relationships, and add a wait-for-it script or similar in your app container to avoid startup race conditions. This ensures reliability in both development and CI/CD environments.


Conclusion

In multi-service environments managed with Docker Compose, service readiness is just as important as service order. While depends_on helps with sequencing, tools like wait-for-it, dockerize, or a custom script are essential for ensuring that container Y waits for container X to be truly ready.

Using this strategy ensures smooth startups, fewer errors, and more stable containerized applications.

Sharing Is Caring:

Leave a Comment