5 min read
How to reduce your AWS bill: 12 practical checks
12 practical checks to reduce your AWS bill, from rightsizing EC2 instances to cleaning up unused storage, snapshots, and idle cloud resources.
Most AWS bills don't grow because of one big mistake. They grow because small amounts of waste accumulate quietly: an oversized instance here, an unused load balancer there, a snapshot nobody deleted two years ago. None of it looks urgent on its own, and that's exactly why it survives.
The checks below are ones we run during every AWS cost and security audit. You don't need special tooling to do most of them yourself. What you need is time, access to the Billing console and Cost Explorer, and a willingness to ask "do we still need this?" about resources that have been running for a while.
1. Turn on Cost Explorer and look at the trend, not just the total
If Cost Explorer isn't enabled, turn it on first. A single monthly total tells you what you spent; a trend by service tells you what's growing. Sort by service and look at the last three months. If EC2 or RDS costs are climbing without a matching increase in usage, that's your starting point.
2. Rightsize EC2 instances based on actual utilization
AWS Compute Optimizer (free, and worth enabling) compares your instance types against actual CPU, memory, and network usage, and recommends smaller or differently shaped instances. It's common to find instances running at 5-10% average CPU that were sized for a peak load that never materialized. Rightsizing is usually the single largest saving available.
3. Check for idle or forgotten instances
Look for instances that are running but have near-zero network traffic and CPU usage over the past two weeks. These are often test environments, old proof-of-concepts, or instances left running after a project ended. Stopping (or terminating, once you've confirmed nothing depends on them) is free money back.
4. Delete unattached EBS volumes
When an EC2 instance is terminated, its attached EBS volumes don't always get deleted with it, depending on how they were configured. Unattached volumes still cost money every month with nothing using them. The EC2 console's "Volumes" view, filtered by state, shows these directly.
5. Clean up old EBS snapshots
Snapshots are cheap individually but accumulate over months or years of automated backups. Check whether your backup tooling is actually pruning old snapshots, or just adding new ones indefinitely. A lifecycle policy (via Data Lifecycle Manager or AWS Backup) should retain what you actually need and delete the rest automatically.
6. Review S3 storage classes
Data that's rarely accessed doesn't need to sit in S3 Standard. S3 Storage Lens or a simple review of bucket access patterns will show which buckets are read often and which are effectively archives. Moving infrequently accessed data to S3 Standard-IA, Glacier Instant Retrieval, or Glacier Flexible Retrieval, using a lifecycle rule, is usually a meaningful and low-risk saving.
7. Check for orphaned load balancers and NAT gateways
Application and Network Load Balancers, and NAT Gateways, bill hourly whether or not they're handling meaningful traffic. It's common to find a load balancer left behind after the service it fronted was decommissioned. NAT Gateways are also one of the more expensive "invisible" costs in a VPC; confirm each one is actually needed and isn't duplicated across availability zones unnecessarily.
8. Consider Reserved Instances or Savings Plans for stable workloads
If you have workloads that run continuously and aren't going away (a production database, a baseline of always-on application servers), on-demand pricing is the most expensive way to pay for them. Compute Savings Plans, in particular, are flexible across instance families and regions, and typically offer a meaningful discount over on-demand for a one or three year commitment. This only makes sense once you've rightsized first; committing to the wrong instance size locks in the wrong spend.
9. Use Spot Instances for interruptible workloads
Batch jobs, CI/CD runners, and other workloads that can tolerate interruption are good candidates for Spot Instances, which can cost significantly less than on-demand. This isn't appropriate for anything stateful or latency-sensitive without careful design, but for the right workload it's a straightforward saving.
10. Check data transfer costs, especially cross-region and to the internet
Data transfer is one of the least visible line items until it isn't. Cross-region transfer, and transfer out to the internet, are billed separately from compute and storage. If you're replicating data across regions more than you need to, or serving large files directly from EC2 or S3 without a CDN, this is worth a closer look. Routing static content through CloudFront can reduce both cost and latency.
11. Audit CloudWatch Logs retention
By default, CloudWatch Logs groups can be set to retain logs indefinitely, which quietly adds up in storage costs, especially for high-volume application logs. Set an explicit retention period (30 or 90 days is common for application logs, longer only where you have a specific compliance reason) instead of leaving it unset.
12. Look for unused Elastic IPs and old AMIs
An Elastic IP address that isn't attached to a running instance is billed hourly. Old custom AMIs, along with their underlying snapshots, also accumulate over time as new versions are built and the old ones are forgotten. Both are quick, low-risk cleanups.
A short checklist
- Cost Explorer enabled, and trend reviewed by service, not just totals
- EC2 instances checked against Compute Optimizer recommendations
- Idle or forgotten instances identified and stopped
- Unattached EBS volumes deleted
- EBS snapshot lifecycle policy in place
- S3 lifecycle rules moving cold data to cheaper storage classes
- Orphaned load balancers and NAT Gateways confirmed as needed
- Savings Plans considered for stable, long-running workloads
- Spot Instances considered for interruptible workloads
- Cross-region and internet data transfer reviewed
- CloudWatch Logs retention set explicitly
- Unused Elastic IPs and old AMIs cleaned up
None of these checks require downtime, and most take longer to explain than to actually do. The time-consuming part is usually the first pass through an account that hasn't been reviewed in a while; after that, a monthly check against Cost Explorer keeps the bill from drifting again.
If you'd rather have someone else run through this list against your account, our AWS cloud support service includes a cost and security audit that covers all twelve checks above, with a written report ranked by potential savings, using a scoped IAM role rather than root access.
Related service
AWS cloud support and management