How to deregister unused AMIs and delete their snapshots
An AMI nothing launches from keeps billing through its snapshots. How to find unused AMIs, check launch templates, and clean them up.
Contents
In short
- An AMI costs nothing on its own: its EBS snapshots carry the cost.
- Deregistering an AMI doesn’t delete its snapshots; you delete them after.
- Check launch templates first, including ones that pick the AMI through an SSM parameter.
Every AMI you register keeps a set of EBS snapshots behind it, one per volume in the image. The AMI itself costs nothing. Its snapshots bill every month at the EBS snapshot storage price, whether anyone launches from the image or not.
Build pipelines are where unused AMIs come from. Each release bakes a new image, old ones are never cleaned up, and a year later an account holds hundreds of images that nothing launches. This guide shows how to find them, how to prove nothing still needs them, and how to remove them with their snapshots.
What an unused AMI costs
The cost is the storage of its snapshots. In us-east-1, standard EBS snapshot storage is $0.05 per GB-month as of October 2026. An image built from a 100 GiB root volume can cost up to about $5 a month, and an image with several large data volumes costs more.
That figure is an upper bound. Snapshots are incremental: a snapshot only stores the blocks that changed since the previous one, and blocks are shared between snapshots of the same volume. AWS says so directly: deleting a snapshot might not reduce your storage costs when other snapshots still reference the same data. Treat the size of an image’s volumes as the most you can save, not a promise.
Deregistering doesn’t delete the snapshots
This is the part people miss. By default, deregistering an AMI has no effect on its snapshots. The image disappears from your list, and you keep paying for its snapshots until you delete them.
There are two ways to avoid that:
- Note the image’s snapshot IDs before you deregister it, then delete them yourself.
- Deregister with
--delete-associated-snapshots, which deletes the image’s snapshots in the same call. Snapshots that another AMI also uses are not deleted.
Find images nothing launches from
An image is a candidate when it is in the available state, is older than 30 days, and no instance or launch template in its region uses it. Start with the images you own in one region:
aws ec2 describe-images --owners self --region us-east-1 \
--query 'Images[?State==`available`].[ImageId,Name,CreationDate,LastLaunchedTime]' \
--output table
LastLaunchedTime tells you when an instance last started from the image. An empty value means it was never launched, or not since AWS started recording it. Images that were never launched, or not in months, go to the top of the list.
Now collect every image ID that something still references. Instances first:
aws ec2 describe-instances --region us-east-1 \
--query 'Reservations[].Instances[].ImageId' --output text | tr '\t' '\n' | sort -u
Then the latest and default version of every launch template. Called with only --versions, this returns those versions for all templates in the region:
aws ec2 describe-launch-template-versions --region us-east-1 \
--versions '$Latest' '$Default' \
--query 'LaunchTemplateVersions[].[LaunchTemplateName,VersionNumber,LaunchTemplateData.ImageId]' \
--output table
If you still use launch configurations, check them too:
aws autoscaling describe-launch-configurations --region us-east-1 \
--query 'LaunchConfigurations[].ImageId' --output text
Any image in the first list that appears in none of the others is unused in that region. Repeat per region you use, since images, instances and templates are all regional.
Check what the lists can’t show
Three things can still depend on an image that looks unused.
Launch templates that read the AMI from SSM. A template’s image can be resolve:ssm:/path/to/parameter instead of an ami- ID. The template then launches whatever image the parameter holds at launch time. Resolve each one before you decide:
aws ssm get-parameter --region us-east-1 --name /path/to/parameter \
--query 'Parameter.Value' --output text
Pinned template versions. An Auto Scaling group can point at a specific template version rather than $Latest or $Default. List what each group uses:
aws autoscaling describe-auto-scaling-groups --region us-east-1 --query 'AutoScalingGroups[].[
AutoScalingGroupName,
LaunchTemplate.LaunchTemplateName
|| MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification.LaunchTemplateName,
LaunchTemplate.Version
|| MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification.Version]' \
--output table
Groups with a mixed instances policy keep their template under MixedInstancesPolicy, which the second half of each || picks up.
Look up any numbered version with describe-launch-template-versions --launch-template-name <name> --versions <n>.
Things outside the account. Disaster recovery runbooks, other accounts the image is shared with, and pipelines that pin an image ID in code. Search your infrastructure repositories for the image ID before you remove it. If an image is a rollback target for the current release, keep it.
Remove an image and its snapshots
Work in this order, one image at a time:
- Record its snapshots and their sizes, so you know what you are deleting:
aws ec2 describe-images --region us-east-1 --image-ids ami-0123456789abcdef0 \
--query 'Images[0].BlockDeviceMappings[].Ebs.[SnapshotId,VolumeSize]' --output table
- Deregister the image. To delete its snapshots in the same call:
aws ec2 deregister-image --region us-east-1 --image-id ami-0123456789abcdef0 \
--delete-associated-snapshots
- If you deregistered without that flag, delete each recorded snapshot:
aws ec2 delete-snapshot --region us-east-1 --snapshot-id snap-0123456789abcdef0
A snapshot that still backs another registered AMI can’t be deleted. That error is a safety net, not a problem: leave that snapshot alone.
If you are unsure about an image, keep a single copy of what matters rather than the whole image. A snapshot of the root volume restores the data; the image can be registered again from it later.
Keep it from coming back
- Retire images in the pipeline that creates them. When a build publishes a new image, have it deregister images older than the last few releases, with
--delete-associated-snapshots. - Tag images at build time with the service, the release and an owner. An image without an owner is the hardest to delete safely.
- Point launch templates at an SSM parameter that the pipeline updates. Old images then stop being referenced as soon as the parameter moves on, which makes them easy to find.
- Review once a month. Sort by
LastLaunchedTimeand work from the oldest.
Old snapshots that never belonged to an image need the same care: see how to clean up old EBS snapshots safely. For the rest of the storage that bills for nothing, read how to find and delete unattached EBS volumes.
What a good cleanup looks like
A cleanup is done when every image you keep has a reason: it backs a running service, a launch template, a rollback, or a recovery plan someone can name. Everything else is gone, with its snapshots. Omni FinOps flags images that are available, older than 30 days and used by no instance or launch template in their region, and marks the ones whose templates resolve through SSM as low confidence, because that check needs a person. You can run the same checks by hand with the commands above. The AWS page lists every other rule it runs.
Mateo Vargas writes Omni FinOps’ cost guides, from the same rules the product runs on every refresh. Prices are list prices in us-east-1 or us-central1 as of October 11, 2026; check your region’s pricing page.