DEV Community

Ronak Sharma
Ronak Sharma

Posted on

Unused AWS Resources: The Silent Driver Behind Expensive Cloud Bills

Ask most engineering leaders whether they know exactly what's running in their AWS account, and you'll get a confident yes. Ask them to actually prove it list every resource currently provisioned and what business purpose each one serves and the confidence usually drops fast. That gap between "I know what's running" and "I can actually account for what's running" is where unused resources live, and it's a bigger gap than almost anyone expects until they're forced to close it.

Here's the specific claim I want to make, because it's narrower than the general "cloud waste" conversation: unused resources aren't a symptom of bad engineering. They're a completely predictable byproduct of how engineering actually works provisioning is fast and cheap to do, decommissioning is slow and nobody's specifically accountable for it, and that asymmetry guarantees accumulation over time regardless of how disciplined a team is. This isn't a story about carelessness. It's a story about incentives, and until the incentives change, the accumulation doesn't stop on its own.

*Provisioning Is a Decision. Decommissioning Is an Afterthought. *

This asymmetry is the actual root cause, and it's worth sitting with because it explains why this problem shows up at literally every company we've worked with, regardless of engineering quality. When someone needs a resource, there's a clear trigger, a clear owner, and usually urgency behind it a feature needs to ship, a test needs an environment, a migration needs somewhere to land. Provisioning gets done because something specific depends on it happening now, and that dependency creates natural accountability. Someone requested it. Someone's waiting on it. It gets built.

Decommissioning has none of that. Nothing urgent depends on deleting a resource nobody's using that's precisely the problem, the absence of urgency is what makes it invisible. There's rarely a clear individual owner responsible for going back and cleaning up once the original need has passed, and "I'll clean that up later" is a promise made constantly and kept rarely, not because anyone's careless but because "later" never arrives with the same forcing function that "now" had. The sprint ends, the project ships, the engineer moves to the next priority, and the resource just continues. Nobody made an active decision to keep paying for it. It simply never received an active decision to stop.

*EBS Volumes: The Classic, Underestimated Case *

When an EC2 instance terminates, its attached EBS volumes don't automatically disappear unless specifically configured to do so, and that configuration detail gets missed constantly, especially in environments where instances get created and destroyed frequently as part of normal development or testing cycles.

The volume just sits there afterward, fully billed, holding data nobody's actively using, waiting indefinitely for someone to either reattach it to something or explicitly delete it neither of which tends to happen without a specific reason prompting it. We've seen accounts with genuinely hundreds of unattached volumes accumulated over a few years of normal operation, representing thousands of dollars a month in storage costs for data that, in a lot of cases, nobody could even confidently identify anymore once we started asking what was actually on each one. In more than one audit, the honest answer from the team was "we're not sure, better safe than sorry" which is a reasonable instinct applied to the wrong problem, since the actual risk of deleting an unidentified volume is usually much lower than the cost of indefinitely storing one nobody can account for.
**
Idle Compute: Running Doesn't Mean Working
**
An EC2 instance that's technically running and passing health checks isn't the same thing as an instance that's actually doing useful work. Plenty of instances sit at genuinely minimal utilization a development environment nobody's touched in months, a proof-of-concept that proved its point and then just kept running afterward, a service that got replaced by something else but never formally decommissioned because nothing broke when the old one kept running alongside the new one.

These don't show up as an obvious problem in any monitoring dashboard, because the instance is healthy by every metric that typically gets watched it's just not delivering any actual value while it runs. Regular review of genuine utilization, not just uptime or health status, is the only way this category gets caught, and it requires someone specifically asking "is this still needed" rather than just confirming "is this still working," which are very different questions that most monitoring tools only answer the second one of. A dashboard full of green checkmarks tells you nothing broke. It tells you nothing about whether anything mattered.

*RDS Instances Left Running Past Their Purpose
*

Database instances are particularly prone to this pattern, because there's a real, legitimate hesitation around deleting anything that might contain data someone eventually needs. That hesitation is reasonable in isolation. In aggregate, it means RDS instances from completed projects, deprecated applications, or one-off analysis work tend to linger far longer than the actual data inside them justifies, because "better safe than sorry" has no natural expiration date attached to it.

The fix isn't "delete cautiously and hope." It's assigning genuine expiration reviews to non-production database instances specifically a defined checkpoint where someone actively confirms continued need, rather than assuming continued need by default simply because nobody's raised an objection. Silence isn't the same thing as confirmation, and treating it that way is exactly how these instances end up running for years past their actual usefulness. A quarterly checkpoint that requires an active "yes, still needed, here's why" answer catches this reliably. A policy that only reacts to someone flagging a problem doesn't, because nobody's incentivized to flag a problem that's just quietly costing money in the background rather than actively breaking anything.

*Load Balancers Pointing at Nothing
*

This is a specific, easy-to-verify case worth calling out directly: load balancers configured to route traffic to backend targets that no longer exist. The load balancer itself keeps running and keeps billing, technically operational, routing traffic toward a target group that's effectively empty, because whatever it was originally built to serve got migrated, deprecated, or replaced without anyone circling back to the load balancer sitting in front of it.

These are genuinely straightforward to identify check target group health and actual backend membership and they're consistently missed anyway, mostly because nobody's specifically responsible for auditing load balancer configuration on any regular cadence. It's not a hard problem to solve. It's a genuinely unowned one, and unowned problems don't get solved just because they're technically easy to fix once someone finally looks.

Unused Elastic File System and Storage Allocations

EFS and similar storage services often get provisioned generously upfront, sized for anticipated need rather than actual current need, and then never revisited once real usage patterns become clear months later. Storage that's allocated but substantially underutilized represents ongoing cost for capacity that isn't actually serving its intended purpose, sitting there because downsizing storage feels like more operational risk and effort than it's usually worth to anyone's individual priorities in a given sprint.

Periodic review against actual usage not the original provisioning estimate made before real usage data existed surfaces this reliably, but only if someone's actually doing that review on a defined schedule rather than treating initial sizing as a permanent, correct decision that doesn't need revisiting. The original estimate wasn't wrong when it was made. It's just rarely updated once reality diverges from it.

Why Standard Monitoring Doesn't Catch This

Here's the part that explains why this problem persists even at companies with genuinely solid monitoring practices: most monitoring is built to answer "is this working correctly," not "is this still needed." Those are fundamentally different questions, and a resource can score perfectly on the first one while being a complete waste on the second, indefinitely, without a single alert ever firing to flag it.

Cost anomaly detection tools help with sudden spikes a resource that jumped from $50 to $500 a month gets flagged reasonably well by most tooling available today. They're structurally much worse at catching quiet, steady accumulation a resource that's been costing $50 a month, unchanged, unnoticed, for two straight years. Nothing about that pattern trips a typical anomaly threshold, because nothing about it is anomalous. It's just persistently, invisibly wasteful, which is a different failure mode than the one most cost monitoring is actually built to catch. And because it's not anomalous, it doesn't compete for attention against the things that are actively alarming it just sits there, patiently, month after month, until someone happens to go looking specifically for it.

What Actually Closes the Gap

Given that the root cause is a structural asymmetry between provisioning and decommissioning, the fix has to address that asymmetry directly, not just add another monitoring dashboard on top of the same broken incentive structure:

Tagging requirements enforced at resource creation, including an owner and an intended lifespan where that's knowable at provisioning time, not retrofitted later once ownership's already unclear

Scheduled reviews with actual teeth a defined cadence where resources get confirmed as still-needed or explicitly decommissioned, rather than defaulting to "keep running" by inertia because nobody raised a specific objection

Automated identification of genuinely idle resources, flagged based on real utilization data rather than uptime or health status alone, since those measure the wrong question

Clear individual ownership for decommissioning, not just for provisioning if nobody's specifically accountable for cleanup, cleanup reliably doesn't happen at any meaningful scale, regardless of how good everyone's intentions are

None of these are complicated to implement individually. What's hard is sustaining them, because none of them have the natural urgency that provisioning has. That's exactly why they need to be built into process rather than left to individual initiative initiative is precisely the thing that reliably runs out once the immediate pressure that would have sustained it is gone.

The Actual Point

Unused resources aren't evidence that an engineering team is careless. They're the predictable, structural result of provisioning being easy and urgent while decommissioning is hard and optional and that asymmetry exists at every company running real infrastructure, not just the ones with weak practices.

The organizations actually controlling this cost aren't the ones with perfect engineering discipline. They're the ones who built a genuine process for closing that gap, instead of just hoping good intentions would close it on their own, which reliably, everywhere we've seen it tried they don't.

Top comments (0)