Understand depends_on in Docker Compose

Razvan Ludosanu
Razvan LudosanuFounder, learnbackend.dev
Published: January 31, 2024

The short answer

In Docker Compose, depends\_on field is used to express the dependencies between the services of an application and specify the order in which these services should be started and stopped.

In this example, the api service depends on the database service. When using the docker compose up command, Compose will start the database service first, then start the api service:

Bash
version: '3'

services:
  api:
    build: .
    depends_on:
      - database
  database:
    image: postgres

You can learn more about building applications running PostgreSQL with our article on how to launch PostgreSQL with Docker Compose.

Easily retrieve this syntax using Warp AI feature

If you’re using Warp as your terminal, you can easily retrieve this syntax using the Warp AI feature:

Entering docker compose depends\_on in the AI question input will prompt a human-readable step by step guide including code snippets.

Controlling the services startup with conditions

By default, Compose only ensures that the services listed under the depends\_on property are started before the dependent service. This means that Compose doesn't guarantee that these services are fully operational and ready to process requests, but only that their containers are running.

It is however possible to set conditions to define when one service should start or wait for another service to reach a specific state. These conditions are defined in the condition property and take three possible values: service\_started, service\_healthy, and service\_completed\_successfully.

The service\_started condition

This condition is the default condition used by Compose and only checks whether the service's container has started, without verifying the service's internal state or health.

In this example, Compose will first start the database service, then start the api service once the database service's container has started.

Bash
version: '3'

services:
  api:
    build: .
    depends_on:
      database:
        condition: service_started
  database:
    image: postgres

The service\_healthy condition

This condition is used to ensure not only that the service's container has started but also that the service inside the container has successfully passed a health check. It ensures that the service is fully operational and ready to accept requests.

It is often combined with the healthcheck property that allows developers to define a custom health check for a given service. You can learn more about this property by reading the official Compose documentation page.

In this example, Compose will first start the database service, execute the pg\_isready command specified in the healthcheck.test property, and then start the api service if the value returned by the test command is 0.

Bash
version: '3'

services:
  api:
    build: .
    depends_on:
      database:
        condition: service_healthy
  database:
    image: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]

The service\_completed\_successfully condition

This condition is used to ensure that the service's container not only starts and runs, but also completes its execution successfully. It's useful in scenarios where the dependent service is a one-time job or task, such as a data migration script, and you want to make sure it finishes without errors before starting another service.

To use service\_completed\_successfully, you should ensure that the dependent service exits with a zero status code upon successful completion.

In this example, Compose will first start the database service, execute the pg\_isready command specified in the healthcheck.test property, start the migration service if the value returned by the test command is 0, and finally start the api service if the exit status of the migration service's container is also 0.

Bash
version: '3'

services:
  api:
    build: .
    depends_on:
      database:
        condition: service_healthy
      migration:
        condition: service_completed_successfully
  database:
    image: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
  migration:
    image: migration-tool

Restarting services manually

When set to true, the restart property allows you to automatically restart the dependent service whenever you perform a manual restart or operation using the docker compose command.

It's important to note that this setting doesn't affect the automated restart policy defined in the  service itself that is typically managed by the container runtime when the container exits unexpectedly.

In this example, Compose will restart the api service if the database service is manually restarted using the docker compose restart command. But it won't be restarted if the database service crashes and is restarted due to the always restart policy.

Bash
version: '3'

services:
  api:
    build: .
    depends_on:
      database:
        restart: true
  database:
    image: postgres
    restart: always

You can learn more about the restart command by reading the official Docker documentation page.

Depending on external services

The depends\_on property only works for services defined within the same compose.yaml file. If your application relies on external services, like a database hosted on a remote server, you'll need to implement custom retry logic in your application to handle dependencies gracefully.

Using wait-for scripts

One way to achieve this is to use a "wait-for" script, that will periodically check if the external service is available before proceeding with your application's startup.

For example, the following script will check every 3 seconds if the status code of the HTTP response sent by the service's /health endpoint located at 127.0.0.1:8080 is 200. It will then exit with a value of 0 if successfully connected to the service or with a value of 1 after 5 unsuccessful attempts.

Bash
#!/bin/bash

HOST="127.0.0.1"
PORT="8080"
MAX_ATTEMPTS=5
DELAY_BETWEEN_ATTEMPS=3

attempt=1

while true; do
  test=$(curl -s -I "$HOST:$PORT/health" | head -n 1 | cut -b 10-12)
  if [ "$test" == 200 ]; then
    exit 0
  fi

  sleep "$DELAY_BETWEEN_ATTEMPS"

  attempt=$((attempt + 1))
  if [ "$attempt" -gt "$MAX_ATTEMPTS" ]; then
    exit 1
  fi
done

This script can then be packaged into a standalone image running on a lightweight distribution such as Alpine Linux, and executed using the service\_completed\_successfully condition as demonstrated in the following example:

Bash
version: '3'

services:
  website:
    build: .
    depends_on:
      api:
        condition: service_completed_successfully
  api:
    image: wait-for-api

While the depends\_on property is used to express the dependencies between the services of an application, the links property is used to establish network communication between containers, which can be particularly useful for microservices architectures.

It allows one container to access services provided by another container using a specific alias, but doesn't whatsoever guarantee the availability or readiness of these services.

Written by
Razvan Ludosanu
Razvan LudosanuFounder, learnbackend.dev
Filed under

Related articles


Learning Docker (The Easy Way) Using LazyDocker & Warp

A concise guide to learning Docker using Lazydocker. Highlights Docker’s benefits and takes advantage of Warp's AI features for a quick setup.

Run SSH In Docker

Learn how to launch and connect to a containerized SSH server in Docker using password-based authentication and SSH keys.

Remove a Docker Image

Learn how to remove a Docker image locally, on a Docker registry, and on Artifactory.

Override the Container Entrypoint With docker run

Learn how to override and customize the entrypoint of a Docker container using the docker run command.

The Dockerfile ARG Instruction

Learn how to define and set build-time variables for Docker images using the ARG instruction and the --build-arg flag.

Start a Docker Container

Learn how to start a new Docker container from an image in both the foreground and the background using the docker-run command.

Stop All Docker Containers

How to gracefully shutdown running containers and forcefully kill unresponsive containers with signals in Docker using the docker-stop and docker-kill commands.

Set Docker Container Hostname

Learn how to set, change and match a docker container hostname.

How To Use An .env File In Docker Compose

Learn how define and pass environment variables to Docker containers using an .env file in Docker Compose.

Use An .env File In Docker

Learn how to write and use .env files in Docker to populate the environment of containers on startup.

Restart Docker Containers

Learn how to restart Docker containers automatically with restart policies and manually using the docker restart, docker start, docker stop and docker kill commands.

Run Bash Shell In Docker

Start an interactive shell in Docker container