Before You Delete What the Scanner Found: The Check Each Kind of Waste Needs First
A waste finding is a lead, not a delete order. For six common AWS findings (unattached EBS volumes, stopped instances, idle load balancers, idle DynamoDB tables, S3 buckets with no lifecycle rule, EFS file systems with no mount targets), the one check to run before you remove anything, and the order to do it in.

A scanner tells you what looks unused. It cannot tell you what is unused.
Those are different sentences, and the gap between them is where people lose data. A volume in the available state is not attached right now. That is all it says. A runbook, a launch script or a restore plan may still point at it by ID.
So treat every finding as a lead. Below are six common ones, the single check each needs before you remove anything, and the order to do it in. The check text comes from the risk notes our own detectors attach to each finding. The AWS behaviour comes from the AWS docs linked in each section.
1. Unattached EBS volume
We flag: a volume in the available state, attached to nothing.
Check first: whether anything still needs the data on it. Volumes get left behind when an instance is terminated, or when someone restores a snapshot to look at it and never comes back.
Order:
- Snapshot the volume.
- Wait until the snapshot state is
completed. - Delete the volume.
A snapshot bills only for the data it stores, so it is a cheap safety net. After the delete, the snapshot restores as a new volume with a new ID. If something references the old ID, it will not find it. That is the thing to grep for in your launch templates and runbooks before step 3.
AWS reference: Delete an Amazon EBS volume and Create an Amazon EBS snapshot.
2. Stopped instance with EBS storage
We flag: an instance in the stopped state that still has EBS volumes attached. You are not paying for compute, but the volumes keep billing.
Check first: whether anyone may want this machine back. Stopped often means "I will look at that later."
Order:
- Create an AMI from the instance.
- Terminate the instance.
- Look for volumes that survived the termination, and delete them separately.
Step 3 is the one people miss. Terminating an instance does not delete a volume whose DeleteOnTermination flag is off. Those stay behind as unattached volumes, which sends you back to section 1.
One more cost note from the AWS docs: creating an AMI creates snapshots of the instance's volumes, and you are charged for those snapshots until you deregister the AMI and delete them. The AMI is a way to keep the machine, not a free copy.
AWS reference: Create an Amazon EBS-backed AMI and Deregister an AMI.
3. Idle load balancer
We flag: a load balancer with no healthy targets, or no requests over the lookback window.
Check first: DNS. Before you delete the load balancer, confirm that no record in Route 53 or at an external DNS provider still points at it. A name that resolves to a deleted load balancer is an outage you caused to save a fixed hourly fee.
Order:
- Search your DNS zones for the load balancer's hostname.
- Check for a deployment in flight that is about to register targets.
- Delete the load balancer.
The detector's own note says the same two things: verify no DNS points here, and check for pending deployments.
AWS reference: Delete an Application Load Balancer.
4. Idle DynamoDB table
We flag: a table with zero consumed reads and zero consumed writes over the monitoring window.
Check first: DynamoDB Streams consumers. A table can be quiet for the table's own traffic while something downstream still reads its stream. Check what is subscribed before you decide the table is dead.
Order:
- Look for stream consumers.
- Search your code and infrastructure definitions for the table name.
- If you are not sure, switch the table to on-demand billing instead of deleting it. You stop paying for idle provisioned capacity and keep the data.
Switching billing mode is the cheap way to be wrong. Deleting a table is the expensive way.
AWS reference: Change data capture for DynamoDB Streams.
5. S3 bucket with no lifecycle rule
We flag: a large bucket with no lifecycle configuration, so everything sits in S3 Standard indefinitely.
Check first: how the data is read. A lifecycle rule is the least destructive fix on this list, but "move it to a colder class" is still a decision about access patterns.
Order:
- Add a transition rule first, for example Standard to Standard-IA after 90 days.
- Watch it for a billing cycle.
- Only then consider an expiration rule.
Transition before expire is the whole point. A transition changes the price. An expiration deletes the object.
Two AWS details to know before step 1. By default, objects smaller than 128 KB do not transition, because AWS charges a transition request per object and for tiny objects that can cost more than the storage saves. And if you move objects out of a class with a minimum storage duration early, you pay for the remainder of that duration.
AWS reference: Transitioning objects using Amazon S3 Lifecycle and Managing the lifecycle of objects.
6. EFS file system with no mount targets
We flag: an Amazon EFS file system with no mount targets. Without a mount target, nothing in your VPC can read or write it, but you still pay for the stored data.
Check first: that it is not simply mid-setup. A file system someone created an hour ago, before adding mount targets, looks identical to one abandoned a year ago. Check its age and ask.
Order:
- Confirm it is not being set up right now.
- Back up the data with AWS Backup or DataSync.
- Delete the file system.
Deleting an EFS file system is permanent. The backup is the only way back.
AWS reference: Deleting an Amazon EFS file system.
The pattern
Every check above is the same question in a different costume: what still depends on this? A snapshot, an AMI, a DNS record, a stream consumer, a transition rule and a backup are all ways to ask it cheaply before you ask it expensively.
Two things follow for how you run a scan.
First, read the finding's risk note before you act on its action line. The scanner's job is to point. Yours is to decide.
Second, keep the tool read-only while you decide. The local CLI is built that way: it only makes read calls, and it refuses anything else. How that guard works is in the guard in front of every AWS call. If you are reviewing someone else's account with credentials you already hold, a client cost review with the credentials you already have walks through the run.
If you do this for several accounts, there is a page for consultants and MSPs.
Run it yourself
The CLI is free and source-available (FSL-1.1-ALv2). It runs on your machine, reads your AWS account with your own credentials, covers 20 AWS services, and sends nothing to CloudWise.
pip install cloudcostwise
cloudcostwise scan --profile my-profile --regions all
Read-only, free, a few minutes. Start at cloudcostwise.io.
Find this waste in your own account
Run the free scanner on your own machine. Read-only, no signup, and nothing is sent to CloudWise.
$ pipx install cloudcostwise
What it checksPrefer a dashboard? Start a free hosted scan →