You can control the startup order of containers within an Amazon ECS task definition using the dependsOn attribute, but not directly within the taskDefinition itself. Instead, dependsOn is a property of ECS services or tasks when you launch them, allowing you to define dependencies between containers within the same task. This is crucial for scenarios where one container needs to be initialized or ready before another can start.

Let’s see this in action. Imagine you have a web application container that needs a database container to be running and accessible before it starts its own initialization.

Here’s a simplified task definition:

{
  "family": "my-app-with-db",
  "containerDefinitions": [
    {
      "name": "database",
      "image": "postgres:13",
      "portMappings": [
        {
          "containerPort": 5432,
          "hostPort": 5432
        }
      ],
      "environment": [
        {"name": "POSTGRES_USER", "value": "myuser"},
        {"name": "POSTGRES_PASSWORD", "value": "mypassword"},
        {"name": "POSTGRES_DB", "value": "mydatabase"}
      ]
    },
    {
      "name": "webapp",
      "image": "my-docker-repo/my-webapp:latest",
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80
        }
      ],
      "environment": [
        {"name": "DATABASE_HOST", "value": "localhost"},
        {"name": "DATABASE_PORT", "value": "5432"},
        {"name": "DATABASE_USER", "value": "myuser"},
        {"name": "DATABASE_PASSWORD", "value": "mypassword"},
        {"name": "DATABASE_NAME", "value": "mydatabase"}
      ]
    }
  ],
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "1024",
  "memory": "2048"
}

In this taskDefinition, we have two containers: database and webapp. The webapp needs the database to be up and running.

To enforce this dependency, we don’t modify the taskDefinition. Instead, we use dependsOn when defining the ECS service or when running a standalone task.

When creating an ECS service using the AWS CLI, you’d include the dependsOn configuration:

aws ecs create-service \
  --cluster my-cluster \
  --task-definition my-app-with-db \
  --service-name my-app-service \
  --desired-count 1 \
  --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-xxxxxxxxxxxxxxxxx],securityGroups=[sg-yyyyyyyyyyyyyyyyy]}" \
  --load-balancers targetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/my-target-group/abcdef1234567890,containerName=webapp,containerPort=80 \
  --placement-constraints '[{"type":"memberOf","expression":"attribute:ecs.cluster-name == my-cluster"}]' \
  --service-registries registryArn=arn:aws:ecs:us-east-1:123456789012:service-registry/my-service-discovery-namespace/my-service-discovery-name,containerName=webapp,containerPort=80 \
  --deployment-configuration "minimumHealthyPercent=100,maximumPercent=200" \
  --health-check-grace-period-seconds 60 \
  --enable-execute-command \
  --platform-version LATEST \
  --depends-on '[{"containerName":"database","condition":"START"},{"containerName":"webapp","condition":"START"}]'

Wait, that’s not quite right. The dependsOn attribute is not a top-level parameter for aws ecs create-service. The dependsOn functionality is actually part of the ECS Task definition itself, but it’s applied at the container level, not the task level.

Let’s correct this. The dependsOn attribute is specified within the containerDefinitions array of the task definition. This is a common point of confusion.

Here’s the corrected task definition:

{
  "family": "my-app-with-db",
  "containerDefinitions": [
    {
      "name": "database",
      "image": "postgres:13",
      "portMappings": [
        {
          "containerPort": 5432,
          "hostPort": 5432
        }
      ],
      "environment": [
        {"name": "POSTGRES_USER", "value": "myuser"},
        {"name": "POSTGRES_PASSWORD", "value": "mypassword"},
        {"name": "POSTGRES_DB", "value": "mydatabase"}
      ],
      "essential": true,  // Essential containers must start for the task to be considered healthy
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/my-app-with-db",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "database"
        }
      }
    },
    {
      "name": "webapp",
      "image": "my-docker-repo/my-webapp:latest",
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80
        }
      ],
      "environment": [
        {"name": "DATABASE_HOST", "value": "localhost"},
        {"name": "DATABASE_PORT", "value": "5432"},
        {"name": "DATABASE_USER", "value": "myuser"},
        {"name": "DATABASE_PASSWORD", "value": "mypassword"},
        {"name": "DATABASE_NAME", "value": "mydatabase"}
      ],
      "dependsOn": [
        {
          "containerName": "database",
          "condition": "START"
        }
      ],
      "essential": true,
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/my-app-with-db",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "webapp"
        }
      }
    }
  ],
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "1024",
  "memory": "2048"
}

The key change is the addition of the dependsOn array within the webapp container definition.

Here’s what’s happening:

  • "containerName": "database": This specifies which container the current container (webapp) depends on.
  • "condition": "START": This is the crucial part. It means the webapp container will only start after the database container has successfully started. Other conditions include HEALTHY (if the depended-on container has a health check defined and passes it) and COMPLETE (for jobs where a container should run to completion).

When ECS launches a task with this definition, it orchestrates the container startup sequence. It will first ensure the database container is running and its status is RUNNING. Only then will it proceed to start the webapp container. If the database container fails to start, the webapp container will not be started, and the task will be marked as unhealthy, allowing ECS to handle remediation (e.g., restarting the task).

The essential flag is also important here. For a task to be considered healthy, all containers marked as essential: true must be running. If database (marked essential) fails to start, the task will fail. If webapp (also essential) depends on database and database starts but webapp has an issue, webapp will be restarted. If webapp’s dependency condition (START) isn’t met (because database failed), webapp won’t even attempt to start, and the task will ultimately fail due to the database container not being RUNNING.

This dependsOn mechanism is a powerful way to ensure that your multi-container tasks start in a predictable and functional order, especially when dealing with dependencies like databases, caches, or initialization services. It prevents your application containers from trying to connect to services that aren’t yet available, leading to more robust and reliable deployments.

The most surprising thing about dependsOn is that it doesn’t guarantee the health of the dependent container unless you explicitly use the HEALTHY condition and have a health check configured for that container. The START condition simply means the container’s RUNNING state has been achieved, not that it’s fully initialized and ready to serve traffic.

This is why you often see patterns where a "waiter" or "readiness" container is introduced. This waiter container might poll the database’s port (e.g., nc -vz database 5432 or pg_isready) or check a health endpoint, and only exit successfully when the dependency is truly ready. The main application container would then depend on this waiter container to be COMPLETE.

The next concept you’ll likely explore is how to handle more complex dependency chains or how to ensure a container is not just started but also healthy before another container proceeds.

Want structured learning?

Take the full Ecs course →