Skip to content

How to Control Service Startup Order with depends_on in Docker Compose

DodaTech 2 min read

In this tutorial, you'll learn about How to Control Service Startup Order with depends_on in Docker Compose. We cover key concepts, practical examples, and best practices.

The Problem

Your Docker Compose app has a web service that connects to a database, but the web service starts before the database is ready, causing connection errors like ECONNREFUSED or Cannot connect to MySQL.

Quick Fix

Basic depends_on — Wait for Container Start

node -e "
const compose = {
    services: {
        db: { image: 'postgres:16' },
        app: {
            image: 'myapp',
            depends_on: ['db']
        }
    }
};
console.log(JSON.stringify(compose, null, 2));
"
# {
#   "services": {
#     "db": { "image": "postgres:16" },
#     "app": {
#       "image": "myapp",
#       "depends_on": ["db"]
#     }
#   }
# }

Basic depends_on only waits for the container to start, not for the service inside it to be ready. The app may still fail if the database takes longer to initialize.

Add a Healthcheck and condition

node -e "
const compose = {
    services: {
        db: {
            image: 'postgres:16',
            healthcheck: {
                test: ['CMD-SHELL', 'pg_isready -U postgres'],
                interval: '5s',
                timeout: '5s',
                retries: 5
            }
        },
        app: {
            image: 'myapp',
            depends_on: {
                db: { condition: 'service_healthy' }
            }
        }
    }
};
console.log(JSON.stringify(compose, null, 2));
"
# { "services": { "db": { ... }, "app": { ... } } }

With condition: service_healthy, Compose waits for the database healthcheck to pass before starting the app service.

Add a Restart Policy for Resilience

node -e "
const compose = {
    services: {
        app: {
            image: 'myapp',
            depends_on: ['db'],
            restart: 'on-failure'
        }
    }
};
console.log('Restart policy configured');
"
# Restart policy configured

Combine depends_on with restart: on-failure so the app retries if the database is not quite ready on the first attempt.

Use Wait-for-It Scripts for Complex Dependencies

# In your Dockerfile, add a wait script
ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh /wait-for-it.sh
RUN chmod +x /wait-for-it.sh
CMD ["./wait-for-it.sh", "db:5432", "--", "node", "app.js"]

For services where a simple healthcheck is insufficient, use a wait-for script that polls the remote port until it is open. This is useful for databases and message queues that do not expose a health endpoint.

Inspect Container Configuration

docker inspect <container-id> --format '{{json .Config}}' | python3 -m json.tool
# {
#   "Hostname": "abc123",
#   "Env": ["PATH=/usr/local/bin:..."],
#   "Cmd": ["node", "app.js"]
# }

Use docker inspect to examine the full configuration of a container. This reveals misconfigurations in environment variables, command arguments, and network settings that may not appear in logs.

Additional Troubleshooting

# Check the error message and stack trace for more context
echo "Review the full error output to identify the root cause"

If the above steps do not resolve the issue, examine the complete error message and stack trace. Often the key detail is in the middle of the traceback rather than the final line. Search for the error message in the project documentation or issue tracker for additional solutions.

Prevention

  • Always add healthchecks to database services in Docker Compose
  • Use condition: service_healthy instead of bare depends_on for production services
  • Add restart: on-failure to application services for defense in depth
  • Use an init script in your app that retries the database connection with exponential backoff

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro