Idle EC2 spend rarely looks like an obviously forgotten instance sitting untouched for a year — though those exist too. More often it's compute that's technically in use but running far more of it, far more of the time, than the workload actually needs, and Auto Scaling Groups are frequently the reason it stays that way instead of naturally scaling down.
Minimum capacity that never lets the group scale down
An Auto Scaling Group's minimum capacity is a floor — the group will never run fewer instances than that, no matter how low actual demand drops. Minimums set at or near peak capacity "to be safe" mean the group is permanently sized for the busiest moment it might ever see, and every instance above what current load needs runs at full cost around the clock. Scaling policies get tuned; the minimum, set once at launch, often doesn't.
Instances running never drop below the Auto Scaling minimum, no matter how far demand falls below it — the shaded gap is paid for either way.
Non-production running like production
Staging and dev environments frequently inherit the same instance types, the same counts, and the same 24/7 uptime as production, even though they're typically only in active use during business hours on weekdays. An environment that's genuinely only needed roughly 40 hours a week is paying for the other 128 hours for no reason other than nobody built a stop/start schedule for it.
Instances nobody remembers the purpose of
Every account accumulates a handful of these over time: an instance spun up for a one-off migration, a proof of concept that got shelved, a "just in case" box someone meant to terminate. Low CPU and low network activity sustained over weeks, combined with no clear owner or tag, is the pattern to look for — not a single low-CPU reading, which can just mean the workload is naturally light.
Where to look
- CloudWatch CPUUtilization, NetworkIn, and NetworkOut over a trailing two-to-four-week window for every running instance, not a spot check.
- AWS Compute Optimizer's recommendations, which are based on actual historical utilization rather than a guess.
- Every Auto Scaling Group's minimum capacity, checked against what current baseline traffic actually requires.
- Non-production environments running around the clock — a scheduled stop/start (via Instance Scheduler or a simple EventBridge-triggered Lambda) is a low-risk change with an immediate, measurable effect on the bill.