compute

Amazon ECS

A managed orchestrator that runs your containers as tasks on either serverless Fargate or your own EC2 instances. Here's when ECS is the right call, what it costs, how it connects to the rest of your architecture, and the container mistakes Design Beaver catches as you draw.

Updated September 6, 2026

What ECS is

ECS runs your containers and keeps them running. You describe a workload in a task definition — which image, how much CPU and memory, which ports, which IAM roles — and ECS launches it as one or more tasks. Group those into a long-running service and ECS holds the desired count steady, rescheduling any task that dies.

Where those containers actually land is the launch type: serverless Fargate, or EC2 instances in a cluster you own and patch. Same ECS either way, same task definitions and services. It sits between raw EC2, where you manage the whole server, and Lambda, where you manage nothing but a function.

Design Beaver models ECS as a container workload with its own ENI, security group, and two separate IAM roles, so it validates as you draw which edges are real and what each one needs.

When to use ECS (and when not to)

Reach for ECS when the work is containerized and runs continuously: a web or API tier behind a load balancer, background workers, queue consumers, or a handful of microservices sharing one cluster. It’s the straightforward answer when you want containers on AWS and don’t want to operate a Kubernetes control plane.

Don’t reach for it for short event-driven request/response logic — Lambda handles that without a cluster and without paying for idle tasks. For a single container with the simplest possible setup, App Runner or a plain EC2 instance is less work. If you need portable Kubernetes APIs or you already live in Helm, that’s EKS, not ECS. And purely static content belongs on S3 behind CloudFront.

Variants: where the containers run

The launch type is the one architectural choice that changes your operational surface. Everything else about ECS stays the same.

OptionWhat it is
Fargate (serverless launch type)defaultAWS provisions and manages the underlying compute; you specify only per-task vCPU and memory and pay per task for what it uses. No instances to patch or scale. Requires the awsvpc network mode. The default choice when you don't want to manage servers.
EC2 (self-managed launch type)Tasks are placed onto EC2 instances in your cluster that you own, patch, and scale (typically via an Auto Scaling group / capacity provider). More operational work, but gives instance-level control (GPUs, specific instance types, denser bin-packing) and can be cheaper at steady high utilization. No per-task Fargate charge — you pay for the EC2 instances.

Pick Fargate when you don’t want to manage servers at all. Pick the EC2 launch type when you need instance-level control — GPUs, a specific instance family — or when high, steady utilization makes owning the instances cheaper than paying per task.

ECS pricing in plain English

ECS itself is free. You pay for whatever compute the tasks sit on, and the launch type decides which meter runs.

There is no additional charge for ECS itself — you pay for the compute the tasks consume, and the price model depends on the launch type. Fargate: pay per task for the vCPU and memory it requests, billed per-second (1-minute minimum) from image pull start until the task stops. EC2 launch type: pay for the underlying EC2 instances and EBS you run the cluster on (standard EC2 pricing), with no per-task Fargate charge.

OptionRepresentative rate
fargateLinux/x86: ~$0.04048 per vCPU-hour + ~$0.004445 per GB-hour. Linux/ARM (Graviton): ~$0.03238 per vCPU-hour + ~$0.003560 per GB-hour.
ec2No per-task charge — billed as standard EC2 instance-hours (plus EBS) for the cluster's instances; see the EC2 entry's pricing

Keeping the bill down

  • Use Fargate Spot (or EC2 Spot capacity) for interruption-tolerant workers to cut compute cost significantly
  • Use the EC2 launch type with dense bin-packing when utilization is high and steady — it can beat per-task Fargate pricing at scale
  • Prefer ARM/Graviton task platforms where the image supports it — cheaper per vCPU-hour and GB-hour than x86
  • Right-size the per-task vCPU/memory to actual usage rather than over-provisioning — on Fargate you pay for what the task requests

us-east-1, Linux (rates vary by region, CPU architecture, and OS). Rates as of 2026-09. Verify at the official pricing pages before using for real cost estimates — these numbers are not kept in sync with AWS pricing changes, and actual cost also depends on data transfer, load balancer, and NAT/VPC-endpoint charges.

How ECS connects to other services

Boxes and arrows hide the part that actually decides whether an ECS architecture works: which role carries which permission, and which network path the traffic takes.

  • RDS

    The containerized application running in an ECS task connects to an RDS database as its data layer (e.g. a task running a web API talking to PostgreSQL)

  • ECR

    ECS pulls the container image for the task from a private ECR repository when the task starts

  • S3security

    The application in the ECS task reads/writes S3 objects via the AWS SDK (e.g. serving user uploads, reading config/assets, writing logs or exports)

    IAM:s3:GetObjects3:PutObjects3:ListBucket

  • DynamoDBsecurity

    The application in the ECS task reads/writes a DynamoDB table via the AWS SDK

    IAM:dynamodb:GetItemdynamodb:PutItemdynamodb:Querydynamodb:UpdateItemdynamodb:DeleteItem

  • SQSsecurity

    The application in the ECS task sends or polls SQS messages via the AWS SDK to decouple components (e.g. a worker service draining a queue)

    IAM:sqs:SendMessagesqs:ReceiveMessagesqs:DeleteMessagesqs:GetQueueAttributes

  • SNSsecurity

    The application in the ECS task publishes messages to an SNS topic via the AWS SDK to fan an event out to multiple subscribers

    IAM:sns:Publish

  • An Application Load Balancer routes incoming HTTP(S) requests to the ECS service's tasks through a target group — the standard way to put a container web/app tier behind a public entry point without giving each task a public IP

  • API Gateway exposes the ECS service over a managed public HTTPS API using a private integration, so an internal container tier in private subnets can be reached without being made publicly routable

  • Secrets Managersecurity

    The containerized app reads a secret (typically the database credentials for its RDS/RDS Proxy connection, or third-party API keys) from Secrets Manager instead of baking it into the image or a plain environment variable

    IAM:secretsmanager:GetSecretValuesecretsmanager:DescribeSecret

  • The containerized app connects to an RDS Proxy endpoint instead of directly to the DB instance, so a bursty or autoscaling task count doesn't exhaust the database's connection limit and failover is faster

The IAM point deserves saying twice, because it’s the mistake that costs the most debugging time. ECS gives a task two roles that run at different moments:

  • The task execution role belongs to the ECS agent and runs before your code does, pulling the image from ECR and wiring up logging. ECR pull permissions live here.
  • The task role belongs to your application code, and it’s what the AWS SDK inside the container uses to call S3, DynamoDB, SQS, or SNS. The SDK picks up its temporary credentials automatically, so there are never access keys baked into the image.

So an ECS → ECR edge is an execution-role concern, while an ECS → S3 edge is a task-role concern. Get them backwards and you get one of two confusing failures: a task that never starts because it can’t pull its image, or a running app that gets AccessDenied on its first API call.

Reaching RDS works differently again — it’s not an IAM question at all. It’s the same VPC, database credentials, and a security-group rule on the DB port. Because tasks use the awsvpc network mode, each task gets its own ENI and security group, so the RDS inbound rule references the task’s security group.

What ECS can’t connect to

Some ECS edges look reasonable on a canvas but don’t exist in AWS. Design Beaver flags them rather than letting you draw an architecture nobody can build.

  • An ECS service is not a Route 53 alias target and nothing resolves a domain straight to it — Route 53 points a domain at the internet-facing thing in front of the tasks (an ALB, or CloudFront), which then routes to the ECS service. There is no direct DNS-to-service edge.

Anti-patterns Design Beaver catches

These are the ECS mistakes that survive a diagram review and then show up as a surprise bill or an exposed database.

Exposing an internet-facing ECS task directly (public subnet, public IP, no load balancer) for a production web service

Why it breaksNo health-checked, single stable entry point, no even distribution across tasks, and every task IP is directly reachable from the internet — task replacements also change IPs, so clients have nothing durable to point at

Do this insteadPut an ALB (or NLB) in front, register the service with an 'ip' target group, and keep the tasks in private subnets

Putting the database (RDS) in a public subnet so the ECS tasks can reach it

Why it breaksNeedlessly exposes the database to the internet when only in-VPC connectivity is required

Do this insteadKeep RDS in a private subnet with Public access off, and allow the ECS task's security group inbound on the DB port

Running Fargate tasks in a private subnet and routing ECR image pulls out through a NAT Gateway

Why it breaksEvery image pull's layer download is billed as NAT Gateway data processing on top of the hourly NAT charge — for image traffic that never needs to leave AWS's network, that's ongoing cost for nothing

Do this insteadAdd ECR interface VPC endpoints (ecr.dkr and ecr.api) plus the S3 gateway endpoint (ECR stores layers in S3) so pulls stay on the private AWS network — cheaper and more secure than routing image traffic through a NAT Gateway

Gotchas that bite in production

  • Two roles, not one. The execution role pulls the image; the task role is for your app’s AWS calls. Splitting them correctly the first time saves an afternoon.
  • Target type must be ip, not instance. A Fargate task — any awsvpc task — is reached at its ENI’s IP, not by an EC2 instance ID. Register the service against an ip target group and ECS keeps task IPs added and drained automatically as tasks cycle.
  • API Gateway can’t target ECS directly. There is no ECS integration. Front the service with an internal ALB or NLB and connect through a VPC Link private integration.
  • Private tasks can’t reach ECR by default. Add the ecr.dkr and ecr.api interface endpoints plus the S3 gateway endpoint. Routing pulls through a NAT Gateway works, but you pay data processing on every layer download forever.
  • A lone internet-facing task is not a web tier. Task replacements change IPs, so clients have nothing stable to point at and no health-checked entry point. Put a load balancer in front.

Further reading

Frequently asked questions

When should you use Amazon ECS?
Use ECS for containerized work that runs continuously — a web or API tier behind a load balancer, background workers, queue consumers, or a set of microservices sharing one cluster. It's the right call when you want containers on AWS without operating a Kubernetes control plane. Skip it for short event-driven request/response logic (Lambda avoids paying for idle tasks), for a single container where App Runner is less work, and when you need portable Kubernetes APIs or an existing Helm ecosystem — that's EKS.
What is the difference between the ECS task role and the task execution role?
They run at different moments and belong to different owners. The task execution role is used by the ECS agent before your code starts — to pull the image from ECR and set up logging, so ecr:GetAuthorizationToken, ecr:BatchGetImage, and ecr:GetDownloadUrlForLayer go here. The task role is what your application code inside the container uses to call S3, DynamoDB, or SQS through the AWS SDK. Putting a permission on the wrong one is the most common ECS IAM mistake, and it produces two different symptoms — a task that can't pull its image, or an app that gets AccessDenied at runtime.
Can API Gateway connect directly to an ECS service?
No. There's no ECS integration type in API Gateway. You put an internal ALB or NLB in front of the ECS service and connect API Gateway to it through a VPC Link private integration. Design Beaver models the VPC Link hop rather than letting you draw an edge that AWS won't build.
How much does Amazon ECS cost?
ECS itself adds no charge — you pay for the compute the tasks consume, and the model depends on the launch type. On Fargate you pay per task for the vCPU and memory it requests, billed per second with a 1-minute minimum, from image pull start until the task stops. On the EC2 launch type there's no per-task charge at all; you pay standard EC2 instance-hours plus EBS for the cluster's instances. Data transfer, load balancer, and NAT charges are separate. Verify current rates on the official Fargate pricing page before estimating a real bill.
Do ECS tasks in a private subnet need a NAT Gateway to pull images from ECR?
They need some network path, but a NAT Gateway is the expensive way to provide it. Every image pull is then billed as NAT data processing on top of the hourly charge, for traffic that never needed to leave AWS. Add ECR interface VPC endpoints (ecr.dkr and ecr.api) plus the S3 gateway endpoint instead — ECR stores image layers in S3, which is why the S3 endpoint is required too.

Validate your ECS architecture as you draw

Design Beaver checks your AWS design in real time — missing queues, invalid connections, and security anti-patterns, caught before you ship. It’s live in beta, free, and runs in your browser. Sign in with Google or GitHub to save your work.

Sign up for free! →

Prefer email? Get new features in your inbox:

Get new features in your inbox

No spam — product updates only, and you can unsubscribe from any email.

← All supported services