An ECS task definition is the blueprint for your application’s containers, detailing everything from the container image to CPU and memory allocations.

Let’s see one in action. Imagine we’re deploying a simple web server using Nginx.

{
  "family": "nginx-webserver",
  "networkMode": "awsvpc",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "nginx-container",
      "image": "nginx:latest",
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/nginx-webserver",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "nginx"
        }
      }
    }
  ]
}

This JSON defines an ECS task named nginx-webserver. It’s configured to run on Fargate (FARGATE in requiresCompatibilities) using the awsvpc network mode. It requests 256 CPU units and 512 MiB of memory. The executionRoleArn is crucial; it grants ECS permission to pull container images and send logs to CloudWatch. The containerDefinitions section specifies our Nginx container, pulling the nginx:latest image, exposing port 80, and configuring CloudWatch Logs for stdout/stderr.

The problem this solves is standardizing and managing containerized applications on AWS. Instead of manually configuring Docker on EC2 instances, ECS task definitions provide a declarative way to describe your application’s runtime environment. This abstraction allows ECS to manage the lifecycle of your containers, schedule them onto appropriate infrastructure (EC2 or Fargate), and ensure they meet your specified resource requirements.

Internally, when you create a task definition, ECS stores this metadata. When you launch a task or a service, ECS uses this definition to provision the necessary resources and launch your containers. The networkMode dictates how networking is handled: awsvpc gives each task its own Elastic Network Interface (ENI) with a private IP address, ideal for Fargate and modern EC2 deployments. bridge or host are older modes, typically used with EC2 launch types.

The cpu and memory values are not just hints; they are resource reservations. For Fargate, these are the exact amounts your task will be provisioned with. For EC2, they influence the placement of your task on an EC2 instance by the ECS scheduler. If an EC2 instance doesn’t have enough available CPU or memory, your task won’t be placed there.

The portMappings are essential for exposing your application. When using awsvpc network mode, the hostPort is often omitted or can be the same as containerPort because the task gets its own IP and port space. For bridge mode, hostPort maps a port on the EC2 instance to the containerPort. The protocol (TCP or UDP) is also specified here.

The logConfiguration is vital for observability. awslogs is the most common driver, sending container logs to CloudWatch Logs. The awslogs-group is the log group name, awslogs-region the AWS region, and awslogs-stream-prefix helps organize log streams within the group. This ensures you can easily retrieve and analyze your application’s logs.

A subtle but critical aspect is the executionRoleArn. This IAM role is not for your application’s code to assume. It’s for the ECS agent itself (or the Fargate infrastructure) to perform actions on your behalf, such as pulling images from ECR, sending logs to CloudWatch, and interacting with other AWS services. Without this role, or if it has insufficient permissions, your containers won’t start correctly, often manifesting as image pull failures or no logs appearing.

Beyond these basics, task definitions can include environment variables, command overrides, entry points, volumes, health checks, and resource limits. Using secrets with AWS Secrets Manager or Parameter Store is a best practice for managing sensitive information, injecting them as environment variables or mounted files into your containers.

The next step after defining your task is usually creating an ECS Service, which manages the deployment and scaling of your tasks.

Want structured learning?

Take the full Ecs course →