10-Step Checklist to Cut Your AWS Bill by 30-70%

A practical, no-fluff checklist I use on every audit to find quick AWS savings within the first week.

By Andrii Votiakov on 2026-04-28

Most AWS bills hide 30-70% in waste. After 15 years of audits, the same patterns show up again and again. Here's the checklist I run through on every engagement.

Quick answer

The fastest wins on any AWS bill, in order: right-size compute (30-60% of compute spend), kill zombie resources (pure waste, usually 5-15%), move logs and cold storage to cheaper tiers, switch to Graviton (20-40% off x86), buy Savings Plans for the floor, audit data transfer for cross-AZ and NAT surprises, tame RDS, review managed services, tag for visibility, and set guardrails. Run all ten and you'll typically cut 30-70% of the bill within 30-60 days.

1. Right-size compute

Pull the last 14 days of CPU and memory metrics for every EC2 instance, ECS task and RDS instance. Anything sitting under 20% average utilisation is a candidate to drop one or two sizes. The EC2 right-sizing 14-day method covers the exact procedure step by step.

Why 14 days? Less than that misses weekly patterns — Monday spikes and weekend troughs change the picture. More than that starts blending in seasonality and deprecated workloads. The sweet spot is two clean weeks at current load.

In practice, I find roughly 25% of instances can drop two sizes and another 25% can drop one. On a fleet of 100 m5.xlarge instances at $0.192/hr each, dropping 50 to m5.large saves around $5,800/month before you touch anything else. On a $30k/month EC2 bill, right-sizing alone routinely yields $8-15k/month.

Quick implementation tip: Enable the CloudWatch agent for memory metrics if you haven't already — CloudWatch doesn't capture memory by default, and memory is the constraint that stops most right-sizing. Once enabled, AWS Compute Optimizer will automatically generate recommendations within 14 days.

2. Kill zombie resources

  • Unattached EBS volumes
  • Old EBS snapshots (anything > 90 days you don't need for compliance)
  • Idle load balancers (zero requests in 30 days)
  • Elastic IPs not attached to anything
  • Old AMIs

These are pure waste. Delete them.

Unattached EBS volumes are billed at full gp3/gp2 rates even when nothing's using them — typically $0.08/GB-month. A single forgotten 1 TB volume from a terminated instance costs $80/month. I regularly find 20-50 such volumes on mid-size accounts, adding up to $500-3,000/month for nothing.

Idle load balancers charge $0.018/hour ($13/month) plus LCU charges even with zero traffic. Old Elastic IPs not attached to a running instance are billed at $0.005/hour ($3.60/month each) — trivial individually, but I've seen accounts with 60+ orphaned IPs.

Quick implementation tip: Run aws ec2 describe-volumes --filters Name=status,Values=available to list all unattached EBS volumes. For ALBs, filter by request count in CloudWatch over the last 30 days — anything at zero can go. AWS Trusted Advisor (Business and above) automates much of this scan.

3. Move logs and backups to cheaper storage

S3 Standard → S3 Intelligent-Tiering or Glacier for anything older than 30 days. CloudWatch Logs retention should rarely be "Never expire" — set per log group based on what you actually query.

S3 Standard costs $0.023/GB-month. Glacier Instant Retrieval costs $0.004/GB-month — an 83% reduction for data you rarely read. For 10 TB of logs sitting in Standard, that's $190/month wasted vs $40/month in Glacier. Over 12 months: $1,800 saved from one lifecycle rule on one bucket.

CloudWatch Logs has an even more common gotcha: default retention is "Never expire." Teams log everything, ship it to CloudWatch, and pay $0.03/GB-month storage indefinitely. I audited one account with 14 TB accumulated over four years — nobody had ever queried any of it past 90 days. Cleanup saved $4,200/month immediately.

Quick implementation tip: For S3, add a single lifecycle rule: transition objects to Intelligent-Tiering at 30 days, Glacier Instant Retrieval at 90 days. For CloudWatch, use this one-liner to find log groups with no retention policy: aws logs describe-log-groups --query 'logGroups[?!retentionInDays].[logGroupName]'. Set retention on every one of those to 30-90 days depending on compliance requirements.

4. Switch to Graviton where you can

ARM-based Graviton instances are typically 20-40% cheaper than x86 equivalents at equal or better performance. Most modern runtimes (Node, Python, Java, Go) work without code changes. The Graviton migration guide has the full sequence including how to handle containers, RDS, and managed services.

Graviton3 (m7g, c7g, r7g) is AWS's latest generation and regularly outperforms equivalent x86 at 20% lower cost. For a service currently running on 10 × m5.xlarge ($1,843/month on-demand), moving to m7g.xlarge costs $1,475/month — saving $368/month per cluster, or about $4,400/year. Do that across five services and you're looking at $22k/year, no code changes required.

RDS on Graviton is the single highest-ROI Graviton move — one parameter change, instance restarts, 20% saved on a bill that's often the second-largest line item in the account.

Quick implementation tip: Start with stateless services and Lambda functions — those are zero-risk Graviton migrations. Build multi-arch container images with docker buildx build --platform linux/amd64,linux/arm64 and roll a 10/90 Graviton/x86 split for a week before full cutover. GitHub Actions now provides free ARM64 runners, so CI build time is no longer an excuse to wait.

5. Buy Savings Plans for steady-state

Once you've right-sized, lock in 1-year Compute Savings Plans for the floor of your usage. 30-50% off on-demand for almost zero commitment risk. The Savings Plans vs Reserved Instances guide covers which type to buy and when.

The single most important rule: right-size before committing. Buying Savings Plans on a fleet you're about to shrink is locking in waste at a discount. Do steps 1 and 4 first, run the new fleet shape for two weeks, then buy.

For a $30k/month on-demand EC2 and Lambda bill with a stable floor of $18k/month, a 1-year Compute Savings Plan (partial upfront) at ~35% discount saves roughly $6,300/month — $75,600/year. That's often the single largest saving in an audit, and it requires no infrastructure changes, just a purchase decision.

Quick implementation tip: Go to Cost Explorer → Savings Plans → Recommendations in the AWS Console. It will tell you exactly how much to buy based on your last 7 or 30 days of usage. Start conservative — buy 60-70% of the recommended amount. You can always buy more later; you can't easily cancel.

6. Audit data transfer

Cross-AZ and cross-region traffic is silent and expensive. Look for chatty services that should be in the same AZ. NAT Gateway charges are often the #1 surprise — VPC endpoints fix most of this.

Cross-AZ traffic costs $0.01/GB each direction — sounds small until you have microservices calling each other 1,000 times a second across AZ boundaries. At 2 KB per call that's 7 TB/month each direction = $140/month per service pair. Multiply by dozens of pairs and it becomes a five-figure line item.

NAT Gateway charges $0.045/hour plus $0.045/GB processed. S3 and DynamoDB traffic through NAT is the most common waste — it can be rerouted through free Gateway Endpoints instead. On an account with heavy S3 access, adding Gateway Endpoints alone often cuts the NAT bill by 30-50%. One client saved $3,800/month from that single change.

Quick implementation tip: In Cost Explorer, filter by Usage Type containing DataTransfer and group by service. You'll see which service is generating the volume. Then check whether free S3/DynamoDB Gateway Endpoints exist in each VPC — aws ec2 describe-vpc-endpoints --filters Name=service-name,Values=com.amazonaws.*.s3. If not, add them in five minutes.

7. Tame RDS

  • Right-size before reserving
  • Move infrequently-queried data to read replicas or Aurora Serverless v2
  • Check if you actually need Multi-AZ on dev/staging
  • Old manual snapshots add up

RDS is usually the second-largest line item on an AWS bill and the one teams touch least. Multi-AZ doubles instance cost — and most teams have it on dev and staging for no real reason. Turning Multi-AZ off on 10 non-prod instances of db.r6i.xlarge saves roughly $2,800/month immediately.

Old manual snapshots are the silent killer. AWS never prompts you to clean them up. An account I audited had 6 TB of snapshots from 2021 — $600/month for backups nobody would ever restore. Running aws rds describe-db-snapshots --snapshot-type manual and deleting anything older than your real RPO is typically a 30-minute job with an immediate monthly payback.

Quick implementation tip: Sort RDS instances by MultiAZ=true and then by Environment tag. Anything tagged dev, staging, or test with Multi-AZ on is an instant saving. For snapshots, delete anything older than 90 days (unless compliance says otherwise). Then buy 1-year RDS Reserved Instances on the production fleet — 35-60% off on-demand, same payback in ~6 months.

8. Review managed services

Every "managed" service has a cheaper alternative if you don't need every feature. Examples: OpenSearch → managed Postgres + pg_search, Kinesis → MSK or Redpanda, MSK → self-managed on Graviton.

AWS managed services are priced at a significant convenience premium. OpenSearch Service on m6g.large.search costs $0.166/hour — roughly 2× the equivalent Graviton EC2 instance. If you're using basic full-text search, pg_search or Elasticsearch on a single Graviton instance can replace it at one-third the cost.

Kinesis Data Streams charges per shard-hour plus per-PUT payload unit. Above a few hundred MB/second, MSK (Managed Kafka) or a self-managed Kafka cluster on Spot/Graviton instances often comes out 50-70% cheaper and removes per-record pricing pressure entirely.

Quick implementation tip: For each managed service, pull the monthly cost, estimate the equivalent self-managed cost (compute + storage + one engineer's maintenance time), and calculate payback. Focus on services costing over $2k/month where you use fewer than 30% of the managed features. Managed databases are usually worth keeping — the operational risk is too high. Managed Kafka, OpenSearch, and ElastiCache are the most common cases to reassess.

9. Tag everything, then chargeback

You can't fix what you can't see. Mandatory tags: team, service, env. Build a weekly Cost Explorer report by tag and send it to the team owners.

Untagged resources are unaccountable resources. When a team sees their $12k/month cloud bill broken out by service and environment, they find savings themselves — because it's their budget. Without tagging, cost ownership stays with the platform team, and everyone else ignores it.

AWS Budget Actions can enforce tag policies: flag or even stop instances that don't carry the required tags. It sounds heavy-handed but it works. One company I worked with went from 60% resource coverage to 97% in three months just by adding automated alerts for untagged resources.

Quick implementation tip: Use AWS Config rule required-tags to alert on every new resource created without mandatory tags. It takes about 20 minutes to set up. For the backlog of untagged existing resources, AWS Tag Editor can bulk-apply tags across resource types. Cost Explorer needs 24 hours to reflect new tags, but the data goes back 12 months once activated.

10. Set guardrails so it stays cheap

  • Budgets with alerts at 50/80/100%
  • Anomaly detection on every account
  • A monthly 30-minute cost review meeting

Optimisation without guardrails reverts. Teams ship new services, engineering habits drift, and within 12 months you're back where you started. The guardrails are what make the savings permanent.

AWS Budgets costs nothing and five minutes to set up. An alert at 80% of expected monthly spend gives early warning before a bill lands. Anomaly Detection (also free in Cost Explorer) uses ML to alert when a service deviates from its pattern — it catches the "Lambda function stuck in a loop" scenario before it runs for a week.

The monthly review meeting matters more than any tool. Thirty minutes with Cost Explorer, one team, one question: "What changed this month and why?" Engineers who see cost as a first-class metric make different architecture decisions. That cultural shift compounds over years.

Quick implementation tip: Create one Budget per AWS account with notifications at 50%, 80%, 100% of last month's spend. Enable Anomaly Detection with a $100/day threshold to start. Set a recurring 30-minute calendar event for the first Monday of each month with a link to Cost Explorer. Takes 15 minutes to set up, saves thousands per year.

Realistic numbers

Here's what a typical engagement looks like on a $30k/month AWS bill when all 10 steps are run:

Step Saving/month
Right-size 120-instance fleet $6,200
Kill 40 zombie EBS volumes, 3 idle ALBs $1,800
S3 lifecycle rules + CloudWatch retention $1,400
Graviton switch on 6 services + RDS $2,800
1-year Compute Savings Plan on new floor $5,100
S3/DynamoDB Gateway Endpoints + NAT cleanup $2,300
RDS: Multi-AZ off on non-prod, old snapshots $2,200
OpenSearch → pg_search on 2 clusters $900
(Tagging + review: future waste prevention) —
(Guardrails: ongoing) —
Total $22,700/month

Starting bill: $30k/month. After 60 days of implementation: $7,300/month. That's a 76% reduction, and it's a real result from a real client, not a projection.

The pattern holds across different bill sizes. On a $100k/month bill, the same steps typically yield $40-65k/month in savings. On a $5k/month bill, expect $1.5-3k/month. The percentage stays roughly consistent; the absolute numbers scale.


Run this list and you'll find savings on day one. If you want a sequenced plan with timelines, the 30-day cloud cost optimisation plan turns these steps into a day-by-day schedule.

If you'd rather have someone do it for you on a pay-for-savings basis, book a call.