# Empty ECS Cluster

> An ECS cluster object is free, so ZopNight reports an empty one at $0, but only after 4 counters all read zero: active services, running tasks, pending tasks, and registered container instances. That last axis is what stops the "default" cluster with idle EC2s attached from being called empty.

Source: https://zop.dev/integrations/aws/recommendations/empty-ecs-cluster
Updated: 2026-08-19

---

## Four zeros, because three lie

Services, running tasks, pending tasks: a cluster can have all three at zero and still not
be empty in the way that matters. The classic case is the `default` cluster with EC2
container instances registered and idling. Their cost is real, but it belongs to the EC2
instances, not the cluster object, and deleting the cluster would strand rather than save.
So the rule reads a fourth counter, registered container instances, and requires all four
axes present and zero before firing. Any missing counter abstains; emptiness is asserted
only on complete evidence.

## Why the finding is worth exactly nothing

The cluster object is [free in every billing sense](https://aws.amazon.com/ecs/pricing/): the aggregator classifies it as
having no cost of its own, with all real spend carried by child resources. An earlier
version gated on a positive cluster cost that could never exist, which made the rule a
permanent zombie that never fired at all. The fix was honesty in the other direction: fire
on the real all-zeros signal, attach an explicit $0, and let the value be the cleanup
action. An empty cluster's cost is cognitive: one more object in every list, one more
"wait, is this used?" in every audit.

## Count the four axes yourself

```bash
aws ecs describe-clusters --clusters my-cluster \
  --query 'clusters[].[clusterName,activeServicesCount,runningTasksCount,pendingTasksCount,registeredContainerInstancesCount]' \
  --output table
```

Four zeros across the row reproduces the finding.

## Before deleting

Empty now is not never-used: check whether CI/CD pipelines or task-run scripts reference the
cluster by name, because `aws ecs run-task` against a deleted cluster fails at the next deploy, not
today. Capacity providers attached to the cluster deserve a look too, since an auto-scaling
group left behind by one can hold real cost. Deletion itself is a single call with nothing
to drain, which is the pleasant consequence of only ever firing on genuinely empty clusters.

## The recurring source

Empty clusters accumulate from tutorials, abandoned experiments, and IaC stacks whose
destroy step failed halfway. If the same names keep reappearing, the fix is upstream in
whichever pipeline creates clusters per-branch or per-experiment without a matching
teardown.
