Every few months a team at work spins up a new service and asks me the same question: "Should this go on ECS, EKS, or just Fargate?" The honest answer is that those three things aren't even the same kind of choice, and conflating them is where most of the confusion starts.

So before I help anyone size instances, I make them separate two decisions: the orchestrator (ECS or EKS) and the capacity model (EC2 you manage, or Fargate that AWS manages). Once you split it that way, the trade-offs get a lot clearer.

The two axes that actually matter

ECS and EKS both schedule containers. Fargate is not a third orchestrator, it's a serverless data plane that either of them can run on. You really have four practical combinations:

OrchestratorCapacityBest when
ECSEC2Cost-sensitive, steady load, you want spot & bin-packing control
ECSFargateSmall teams, no k8s expertise, bursty or low-ops services
EKSEC2You need the k8s ecosystem (operators, CRDs, Helm) and dense packing
EKSFargatek8s API surface but no node fleet to patch, at a per-pod premium

What Fargate costs you (literally)

Fargate bills per vCPU-second and per GB-second with no shared headroom. A task with 1 vCPU and 2 GB in us-east-1 runs about $0.04048/hr for vCPU plus $0.004445/hr per GB, roughly $35/month running continuously. The equivalent slice of an m6i.large you bin-pack yourself is meaningfully cheaper once utilization climbs above ~50%, and cheaper still on Spot.

Fargate's price isn't the per-task rate, it's the utilization you leave on the table because every task is its own billing unit with no neighbors to share slack.

The flip side: with EC2 you pay for the whole node whether it's 30% or 90% full, plus you patch the AMI, manage the ASG, and handle draining. Fargate erases all of that. For spiky, low-volume services the operational savings dwarf the compute premium.

A minimal ECS-on-Fargate service in Terraform

resource "aws_ecs_service" "api" {
  name            = "checkout-api"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.api.arn
  desired_count   = 3
  launch_type     = "FARGATE"

  network_configuration {
    subnets          = var.private_subnet_ids
    security_groups  = [aws_security_group.api.id]
    assign_public_ip = false
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.api.arn
    container_name   = "api"
    container_port   = 8080
  }
}

resource "aws_ecs_task_definition" "api" {
  family                   = "checkout-api"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = "512"   # 0.5 vCPU
  memory                   = "1024"  # 1 GB
  execution_role_arn       = aws_iam_role.task_exec.arn
}

Note the discrete cpu/memory pairs, Fargate only allows valid combinations (e.g. 0.5 vCPU pairs with 1-4 GB). You can't right-size to arbitrary values like you can with raw EC2.

When EKS earns its keep

EKS adds a flat $0.10/hr (~$73/month) per cluster for the control plane, before you've run a single pod. That's trivial at scale and annoying for a handful of services. I reach for EKS when:

  • The team already speaks Kubernetes and wants kubectl, Helm, and operators.
  • You need ecosystem tooling that has no ECS equivalent, KEDA, Istio, Argo, custom CRDs.
  • You're multi-cloud or want portability away from AWS-native primitives.
  • You need dense, heterogeneous bin-packing across many small workloads where Karpenter shines.

If none of those apply, EKS is mostly extra YAML and a control-plane bill. ECS with the AWS provider integrations (ALB, IAM task roles, CloudMap) covers the 80% case with far less to operate.

How I actually decide

  1. No k8s skills + low ops budget? ECS on Fargate. Ship it.
  2. Steady, predictable, cost-sensitive load? ECS on EC2 with Spot for stateless tasks.
  3. Need the k8s ecosystem? EKS, then Karpenter on EC2 for cost, or Fargate profiles for the bits you don't want to babysit.

Takeaways

  • Decide orchestrator (ECS vs EKS) and capacity (EC2 vs Fargate) as two separate questions, not one.
  • Fargate trades a per-task compute premium for zero node management, worth it below ~50% utilization or for bursty load.
  • EKS's $73/month control plane and YAML overhead only pay off when you genuinely need the Kubernetes ecosystem.
  • Default to ECS on Fargate for new services; graduate to EC2 capacity or EKS only when numbers or tooling demand it.