Six AWS cloud cost moves for 2026: idle resource cleanup, EC2 and EBS right-sizing, Savings Plans tradeoffs, egress cuts, budget alarms, and a 30-day plan.
An AWS bill is hard to read not because it is complicated, but because the default view is a payment view — it tells you how much you were charged, not which machine, which environment, or which disk burned the money. To do AWS cloud cost optimization, the first move is not to ask for a discount. It is to switch the bill into a cost view: slice it by service, usage type, tag, and availability zone. If the bill has jumped and you need to find out who moved it, that is a different path - see why your AWS bill jumped.
The six moves below are ordered by benefit-to-effort, not by difficulty. The first three usually recover 30–60% of what is recoverable, and most of them need no architecture change at all. (A note: discounts are one layer of bill optimisation, not the first one — how the five providers differ is set out in cloud discount mechanisms compared.)
Order matters: clean up first (3 days) → right-size next (1–2 weeks) → then commit to discounts (1 month minimum) → only then alarms and governance. Reverse it and you buy a one-year commitment before discovering half the resources are unused.
Thirty minutes to turn the bill into a cost view
AWS gives you three billing interfaces at very different levels of detail. You want Cost Explorer, not the billing page.
- Billing page: totals and invoices. Good for confirming what you paid, useless for finding out why.
- Cost Explorer: multi-dimensional breakdowns by service, usage type, region, tag, and account, with custom period comparison. This is the diagnostic tool.
- Cost and Usage Report (CUR): raw line-item data landed in S3, queried with Athena. Once several people share one account, this is where you end up.
Path is Billing Console → Cost Explorer → Cost and Usage Report. The first two are free. Cost Explorer is free for the first two billing cycles, then billed as a share of the cost of the resources it tracks (small fraction of a percent of monthly spend, minimum around $1/month — check the official pricing page for current rates).
| View | Question it answers | Data lag |
|---|---|---|
| Billing page | How much did I pay in total? | Totals are current |
| Cost Explorer (hourly usage) | Which service or usage type is growing? | Roughly 12–24 hours |
| Cost Explorer (cross-region / resource level) | Which instance, which volume? | Roughly 24–48 hours |
| CUR + Athena | Custom dimensions: team, tag, feature | Usually beyond 24 hours |
Do not expect to understand yesterday completely today. AWS usage data arrives in batches, and aggregate items like cross-region and data transfer charges lag the most — sometimes beyond 48 hours. The first week of a month will always look artificially cheap, so keep it out of month-over-month comparisons or you will conclude your spend collapsed.
Find the five things actually eating your budget
Do not optimise on instinct. Open Cost Explorer and work through these four steps — ten minutes gets you a ranked cost list.
- Group by Service over the previous month and read off the top five shares.
- For the top two or three, switch Group by to Usage type to see whether it is
DataTransfer-Out-Bytes,BoxUsage:m5.large, or something else. - Switch Group by to Region + Availability Zone. On many bills, intra-region cross-AZ traffic shows up as a small but steadily growing line.
- Turn on cost allocation tags and group by
Env,Owner,Service. Untagged spend floating in its own bucket is itself a first-priority problem.
Most small-to-mid teams end up with a shape like this. These are typical ranges, not any one company's actual bill:
| Rank | Cost item | Typical share | Recoverable |
|---|---|---|---|
| 1 | EC2 compute (before discounts) | 30–50% | 20–40% |
| 2 | Data transfer out (cross-AZ, NAT, cross-region, internet) | 10–25% | 30–60% |
| 3 | EBS volumes and snapshots | 8–20% | 15–35% |
| 4 | Managed databases (RDS/Aurora) plus storage and backups | 8–20% | 10–25% |
| 5 | NAT gateways, load balancers, idle public IPs | 5–15% | 50–90% |
Biggest line is not the same as best first move. Rank five has a small share but the highest recoverable amount, and it usually takes one evening. Sort by recoverable amount times speed to fix, not by absolute dollars.
Move 1: shut down what nobody uses
This is the highest-return step and the one most often skipped. Teams usually know waste exists; nobody has actually gone looking. Hand these actions to whoever is on call, or encode them in the IaC pipeline (Terraform/Pulumi), rather than relying on memory.
- Unattached EBS volumes: filter
DescribeVolumesonState=available. A volume is billed at its configured size whether or not it is attached. - Idle Elastic IPs: an EIP with nothing associated to it still accrues an hourly charge.
- NAT gateways spread across availability zones: a NAT Gateway is billed per availability zone. If your multi-AZ design puts one in every zone and one zone carries no real traffic, you are paying a full hourly fee for it.
- Auto Scaling groups scaled to zero, stopped-but-not-terminated instances, long-retained RDS snapshots and old AMIs.
- CloudWatch Log groups with no retention setting: logs accumulate by the gigabyte indefinitely — small-looking, expensive six months later.
- Idle load balancers and snapshots with no dependent chain.
| Check | How | Why it pays |
|---|---|---|
| Unattached volumes | Filter DescribeVolumes on available, confirm, delete | Billed at full provisioned size; deleting fixes it once |
| Idle EIPs | DescribeAddresses and look for entries with no AssociationId | Around $0.005/hour class; 20 zombie EIPs is a few hundred dollars a year (check official pricing) |
| NAT consolidation | Read per-AZ traffic metrics, merge idle zones into one or two | Billed per zone; merging three into one typically removes over half of NAT cost |
| Log retention | Set 30–90 day retention per log group, offload errors to S3 | Often cuts log spend by more than half |
| Snapshot lifecycle | Lifecycle policy expiring anything that is not a current baseline | Stops snapshot volume from only ever growing |
Guard the delete path too. The cleanup itself takes minutes, but a mistaken deletion needs process to contain it: an SCP or IAM policy requiring a ticket or an approval tag before DeleteVolume, or simply stopping first and deleting seven days later so there is a rollback window.
Move 2: right-size instances and disks
After cleanup, the next step is shrinking what is still paying full price but not fully used. Decide from metrics, not intuition.
EC2: look at p95 and memory, not averages
Open Compute Optimizer (no charge). It reads CloudWatch history and recommends downsizing, upsizing, and moves to newer architectures; on EC2 the recommendations look back roughly 12 weeks, which conveniently covers a full weekday/weekend cycle. How to pick a family and region for a given workload: EC2 instance types and regions.
- Judge CPU by p95, not the mean. An instance with a p95 of 15% usually drops a size.
- Memory is often the real bottleneck — Java and Node services allocated generously but running at 30% utilisation is extremely common.
- Do not size to the average. Keep 20–30% headroom. Spikes are normal, and sizing to the mean buys you more restarts and worse p99 latency.
- Changing family often beats changing size: same-performance newer-generation instances run roughly 10–25% cheaper, and Graviton (Arm) is typically 20–40% cheaper on supported workloads. Confirm your dependencies are not x86-native binaries before switching.
EBS: GP3 IOPS and throughput are adjustable
The most common GP3 waste is buying peak spec on day one. IOPS and throughput are adjustable after creation, so start at baseline and climb to your measured p95 rather than one-shot buying max. Use VolumeReadOps and VolumeWriteOps in CloudWatch to pick the level.
Two commonly missed items: when the same data is attached to several instances, the old volume on the retiring instance is not merged automatically and keeps billing in full; and EBS Optimizer now lists optimisable volumes with an estimated saving, which is worth running monthly.
Snapshots are billed separately. You can drop a volume to baseline and the snapshot still bills on its stored capacity — historical snapshots do not get cheaper because you resized the volume. Deleting the old volume and rebuilding the AMI is usually cheaper than rebuilding the AMI and keeping old snapshots.
Move 3: Savings Plans vs Reserved vs Spot
A committed discount is fundamentally flexibility sold for money. Picking wrong does not cost you a small discount — it costs you a year of paying for a commitment you never fill. Full comparison of the three options: Savings Plans vs Reserved Instances.
| Option | Typical discount vs on-demand | Flexibility | Best for |
|---|---|---|---|
| Spot Instances | Up to ~90% off | Lowest; can be reclaimed within ~2 minutes | Batch jobs, rendering, CI, data transformation, interruptible work |
| Compute Savings Plans (1yr / 3yr) | ~10–20% / ~20–30% | Higher; auto-applies across compute usage in one region, including Fargate and Lambda | Teams whose instance mix keeps changing (containers, serverless) |
| EC2 Instance Savings Plans | Similar band to Compute SPs | Applies to EC2 in specific instance families | Load concentrated in a handful of instance families |
| Standard Reserved Instances | ~25–40% at 1yr, more at 3yr | Lowest: locked to one instance family in one region | Load that will not change family for 6+ months |
The decision rules are short:
- Anything that can run on Spot, move it to Spot. Pair it with autoscaling and checkpointing so the system tolerates interruption, and batch cost drops to near a tenth of on-demand.
- Stable EC2 on 2–3 instance families → a one-year Compute Savings Plan. It is insensitive to family changes and much harder to get wrong than an RI. This is the right default for most small teams.
- Do not start with a 3-year term. Exiting early costs real money: selling unused Reserved Instances can incur a fee of up to roughly half the upfront payment, and Savings Plan exchanges and exits carry their own conditions and charges. Buy one year, confirm the load is stable, then decide.
- Commit only the steady-state baseline. Use the floor of your load — usually the overnight low — as the commitment, and leave the elastic part on-demand or on Spot. Over-committing is not refunded; it is the most common way teams lose money here.
Savings Plan scope is widely misunderstood: it applies automatically within a single region and does not carry across regions, and it does not cover data transfer or most managed service charges. Check the applicable-usage preview in the console before committing instead of guessing your coverage.
Move 4: data transfer (egress), the surprise line item
DataTransfer-Out-Bytes is usually the steepest-growing and least designed line on the bill. The root cause is almost always the same: a request leaving from one availability zone is billed at that zone's egress, not at whatever CDN or central exit you thought you had. The full breakdown - transfer has six billing boundaries, and what to do about each - is in why AWS data transfer costs so much.
- Traffic within the same AZ is free; across AZs in one region is billed per GB, and both directions count.
- Cross-region traffic is also billed, typically at a higher rate than cross-AZ.
- NAT gateways charge both an hourly fee and a per-GB processing fee — you pay twice on NAT-routed traffic.
- Internet egress: static assets, API responses, and image downloads all land here, and this is normally the largest piece.
| Scenario | What to do | Rough saving |
|---|---|---|
| Static assets (images, JS/CSS, fonts) | Serve through CloudFront with S3 as origin | CloudFront internet egress is exempt from data transfer charges — often 50–90% off this line |
| Microservice calls crossing AZs | Co-locate replicas of one service in one AZ, or use PrivateLink | Same-AZ calls are free, removing the cross-AZ charge |
| NAT gateway traffic | Consolidate to fewer NAT gateways; use VPC endpoints for S3/DynamoDB | Endpoints use internal paths instead of the per-GB NAT processing fee |
| Cross-region database replication | Relax the replication interval to what the workload tolerates | Halving the interval roughly halves cross-region transfer |
| Log and data export | Compress before sending, or switch to pull-based retrieval | gzip/zstd typically cuts transfer volume by 60–80% |
One action you can take today: in Cost Explorer set Group by to Usage type, filter on DataTransfer, and split by availability zone. You will usually find one or two zones with obviously abnormal traffic — that is almost always a NAT gateway or one unoptimised service bleeding money.
Move 5: use budget alarms as brakes
Optimisation is not a project, it is a habit. Without alarms, accounts give the savings back within three months because new resources, test environments, and misconfiguration all push the bill up quietly. The value of AWS Budgets is not the report — it is that a threshold fires and reaches a human.
- Open AWS Budgets → Create budget → Cost budget, scoped to the account you actually own.
- Set the amount to 1.1–1.2× last month's actual spend, not to your target. Otherwise you alarm every week in month one and everyone learns to ignore it.
- Add 50% / 80% / 100% actual thresholds, plus one Actual vs Forecasted threshold to catch "this month will overshoot by month end".
- Use at least two notification channels: email plus team chat (SNS → Chatbot). An email-only alarm is, in practice, no alarm.
- Turn on Cost Anomaly Detection. It flags changes in consumption patterns against history, catching "this resource suddenly behaves differently" before it shows up as a large bill.
| Alarm type | Suggested thresholds | What it protects |
|---|---|---|
| Actual cost | 50% / 80% / 100% | Caps this month's spend |
| Actual vs forecasted | 10% over forecast | Gives a week of warning before overspend |
| Cost Anomaly Detection | System defaults, tune as needed | Catches single-day abnormal consumption |
| Service usage thresholds | 2× your normal baseline | Spots traffic spikes early |
One more governance rule: cost allocation tags have to be mandatory at creation time. If tagging depends on someone remembering, Untagged typically settles at 15–30% of total spend within six months and you can never explain whose it is. Enforce it with an Organizations SCP or as a required tag in your IaC templates.
Move 6: make cost something a team can manage
Once the six moves are done, the remaining bottleneck is usually not technical — it is who is allowed to decide how much gets spent. This is what determines whether any of it sticks.
- Separate accounts per environment: one for production, one for test. Test environments drift first, and an isolated account turns "shut down staging" into an ordinary operation.
- Scheduled shutdown for test environments: stop at 19:00 on weekdays, all weekend. A 20-instance environment saves tens of hours of on-demand time per month, which is a couple of engineers' salaries.
- A cost checkpoint before launch: every new service needs a projected monthly figure, and anything above a threshold (say $500/month) needs a written architecture review. This is far cheaper than saving money afterwards.
- A 30-minute weekly cost review: look at exactly three things — total trend, top five services, this week's anomalies. Three months of this beats any one-off refactor.
- Make the line items queryable: CUR into S3 plus Athena (billed per bytes scanned, which is very cheap) lets product teams answer "what did this feature cost" without asking an architect.
| Governance action | Cadence | Typical owner |
|---|---|---|
| Share of spend that is untagged | Weekly | Platform / cloud management |
| Idle resource scan and cleanup | Monthly | Platform / cloud management |
| Savings Plan coverage and utilisation | Monthly | Technical lead |
| Cost record for new and retired services | Every release | Service owner |
Two signals worth watching: commitment utilisation below 90% means you are paying for a commitment you are not filling, and any resource with zero usage across 30 days is an explicit cleanup candidate. Both surface problems earlier than the total does.
A 30-day checklist
The whole article compressed into four weeks. Run them in this order and the savings compound linearly:
- Week 1 — see it: break last month down by service, usage type, and AZ; produce a top-10 cost list; turn on cost allocation tags.
- Week 2 — zero it out: delete unattached volumes, idle EIPs, redundant NAT gateways, expired snapshots; set 30–90 day retention on every log group; add scheduled shutdown for test environments.
- Week 3 — right-size: run Compute Optimizer and EBS Optimizer, resize a batch of instances, migrate primary volumes to GP3 with IOPS and throughput dialled down, assess one Graviton migration.
- Week 4 — commit and guard: buy a one-year Compute Savings Plan sized to your steady-state baseline; move batch jobs to Spot; configure 50/80/100% budget alarms and Cost Anomaly Detection notifications.
Across those four weeks, a common outcome is cutting 25–50% of recoverable spend, with a large share of it landing on the very next invoice. What actually decides the long run is after week four: someone reads the alarms, someone fills in the tags, someone scans for idle resources.
A concrete next step for this afternoon: open Cost Explorer, switch to last month, set Group by to Service, and write down the top three shares. Those three numbers are where every optimisation effort you do from here starts. If you cannot pull meaningful data out of your own account, or the structure does not look like what you expected, that is worth fixing on its own — bring us your service inventory, region layout, and last month's billing summary and we will help you separate the genuinely optimisable spend from the necessary baseline.