Do not change anything yet. Drill down in Cost Explorer by service, then by usage type, and check seven sources that keep billing even when nothing looks broken.
Last month the bill was 520. This month the forecast is 780. Nothing was deliberately scaled up, no major release shipped, CPU utilisation looks normal and the application is healthy. This is the kind of bill people misdiagnose most often.
The reflex is to downsize the instances. But both the AWS documentation and real incident write-ups point the same way: the resource you suspect first is usually not the culprit. What tends to grow fastest is data movement - and the resources you assumed had been deleted.
This page is about the investigation process, not a saving checklist - that one is in AWS billing: six actions that actually work.
The first rule: do not change anything yet
The first rule of cost investigation is counter-intuitive: do not optimise before you understand where the money is going.
- Do not rush to terminate instances, downsize, delete snapshots, remove NAT gateways or switch off logging. Those actions may save money, and may also break production.
- The goal here is to locate the cause first, not to save yet. Reverse the order and you may delete something still in use while the real cause keeps growing.
- The bill is not lying to you - it just does not tell you why. That is what this page takes apart.
⛔ Locate first, act second is not caution for its own sake: plenty of unexpected charges only begin after something is deleted. Terminate an instance and its volumes stay behind, and that line item becomes a charge nobody recognises.
Step one: pin the location down with two levels of grouping
Open Cost Explorer, not the billing summary. The difference matters: the summary tells you how much; Cost Explorer tells you why.
Then do three things, in this order:
- Group by service: this immediately shows whether the increase came from EC2, S3, data transfer, or something you had not considered.
- Narrow the date range to the days just before the jump. That tells you when it started, not merely that it happened.
- Group by usage type: this is the step that turns a service-level figure into the specific thing being billed, and it is what the next section covers.
A typical comparison looks like this (figures are illustrative, to show the shape):
| Service | Last month | This month | Change |
|---|---|---|---|
| EC2 | $125 | $132 | +$7 |
| RDS | $91 | $94 | +$3 |
| S3 | $18 | $21 | +$3 |
| Data transfer | $61 | $168 | +$107 |
| NAT gateway | $32 | $96 | +$64 |
| Other | $45 | $48 | +$3 |
What this step usually shows: the service you suspected barely moved, and traffic is what grew. EC2 rose by seven dollars - so "downsize the instances" was the wrong direction from the very start.
Step two: group by usage type - that is where the culprit shows
Service-level grouping only gets you to "EC2 went up". Switch the grouping dimension from service to usage type and entries like these appear:
- DataTransfer-Out-Bytes - outbound traffic, billed per GB.
- DataTransfer-Regional-Bytes - traffic across availability zones or regions.
- NatGateway-Bytes - the volume of data processed by the NAT gateway.
- NatGateway-Hours - the hours the NAT gateway existed.
At this point the question stops being a billing question and becomes an architecture question: what is pushing traffic through these paths? Likely answers include a scheduled job pulling a large dataset, a deployment pipeline repeatedly pulling container images, or a service whose internal calls are being routed out to the internet through the NAT gateway.
Only now is it worth looking at CloudWatch network metrics, and VPC Flow Logs if you need to attribute traffic to a specific resource. Worth remembering: a NAT gateway is billed on throughput, not only on hours - existing is cheap, what it processes is what costs. Official pricing is authoritative. There are six such boundaries in total, and how to cut each one is in why AWS data transfer costs so much.
Seven counter-intuitive sources that keep billing
These seven are called out in the AWS documentation and are the most common real-world sources of unexpected charges. They share one trait: none of them looks like a running thing, and all of them bill.
| Source | Why it keeps charging | How to confirm |
|---|---|---|
| 1. Free tier exhausted | Once the allowance is used up or expires, usage converts to on-demand pricing. The account is not closed and nothing warns you | The free tier page shows current and forecast usage |
| 2. Volumes left behind | Storage volumes do not disappear with the instance. Terminate the instance and the volume stays, still billing | Check the EBS console for unattached volumes |
| 3. Snapshots | Snapshots are independent resources that accumulate over time and are easily forgotten | Sort by creation date and look at the oldest |
| 4. Resources in a disabled region | Turning a region off does not delete its resources. They keep billing, and you can no longer reach them | Terminate everything in a region before disabling it |
| 5. Resources created by other services | Some services create resources in other services on your behalf - instances, volumes, log groups behind a managed service | Watch for services you never enabled when grouping by service |
| 6. Idle load balancers and NAT gateways | They bill for existing (hourly), even with no traffic; a NAT gateway also bills on throughput | Look for instances with no backends or long zero-traffic periods |
| 7. Public IPv4 addresses | The documentation lists address resources as an unexpected-charge source; these rules have changed in recent years | Check the official pricing page - do not trust older articles |
A five-minute self-check: open the consoles behind items 2, 3 and 6 and sort by oldest or least recently used. Orphaned resources cluster there, and cleaning them affects nothing that is still running - one of the few places where acting first is safe.
Closing the account does not stop the billing
This one deserves its own section because the trigger is unambiguous: you closed the account and the bill did not stop.
The documentation is explicit that a bill can still arrive after closure, for reasons including:
- Usage already incurred in the month of closure is billed in the following cycle as normal.
- Active Reserved Instances keep billing until the reservation term expires.
- Active Savings Plans keep billing until the plan term completes.
- Marketplace subscriptions are not cancelled automatically: terminate every software instance under the subscription first, then cancel it in the subscriptions page.
For a period after closure you can still sign in to view surviving resources, past billing, and pay outstanding amounts.
⛔ So "close the account when the project ends" presumes there are no unexpired commitments inside it. Confirm that before closing: any Reserved Instance or Savings Plan still running. Commitment discounts differ by provider (some lock the spec, some commit an amount) - all five compared in cloud discount mechanisms compared; the return and expiry rules for Savings Plans are in how to buy AWS Savings Plans.
Why these resources keep charging
Those seven sources look unrelated, but they share one mental model - replace it and a lot of "inexplicable" billing explains itself:
AWS charges for a resource existing, not for a resource working. A file sitting on your laptop is free. A volume, an address, a load balancer in the cloud costs money simply because it exists.
So the right self-check question is not "is it still running" but "is it still there". That difference decides whether you go and look at the things you assumed would clean themselves up.
Following that model, a bill grows in only three ways: organic usage growth (requests, traffic, storage accumulating), a resource created automatically or simply forgotten (the seven above), and a unit-price step change (allowance exhausted, commitment expired). Work out which one you are looking at first, and the direction is set.
Three settings that warn you in advance
Investigation is reactive. These three take about fifteen minutes together, and they turn "found out at month end" into "found out within days" - which is the real dividing line in billing management:
| Setting | What it does | Why it is worth it |
|---|---|---|
| AWS Budgets | Set a cost or usage threshold with tiered alerts at percentages like 50% / 80% / 100% | Turns "I check it at month end" into "I get told when it crosses a line" |
| Cost Anomaly Detection | Learns your usage patterns, alerts on anomalies, and provides root cause analysis sliced by service, account, usage type and region | Fixed thresholds miss irregular spikes; pattern-based detection handles them |
| Billing alarms on estimated charges | Alerts on forecast spend before the detailed breakdown is available | An early-warning layer on top of budgets |
One more thing that gets skipped and matters just as much: tag your resources (project, environment, owner). Untagged resources are invisible in the bill - when something spikes you cannot attribute it to a team or an environment. Tagging is cheap, and the payoff is that every future investigation can go straight to the answer.
None of this is cost optimisation: it does not save money, it tells you earlier. Only on top of that baseline does it make sense to talk about commitment discounts, because you need a stable baseline to judge them against - see how to buy AWS Savings Plans. And keep the two layers apart: an official discount lowers the unit price on the bill, while settling through a channel lowers what you actually pay - see AWS discounts and reseller pricing.
FAQ
I changed nothing - why did the bill go up?
Separate three causes first: organic growth (requests, traffic and storage accumulating, the most commonly missed), a resource created automatically or forgotten (the seven above), and a unit-price step change (allowance exhausted, commitment expired, pricing rules changed). Each needs a completely different response: the first is architecture work, the second is cleanup, the third is re-costing.
Do I have to wait for the invoice to see the charges?
No. Cost Explorer data is near real-time (with some delay), so you can see the trend within the month rather than waiting for the invoice. That is exactly why the "find out when the bill lands" pattern can be replaced - with anomaly detection, most spikes are identified within days.
Can I get unexpected charges waived?
The documentation states that you can query your bill and contact support about it. Be clear-eyed about the outcome though: asking is not the same as being credited, and any adjustment depends on the specifics and the policy in force - the official channel is authoritative. Better than appealing afterwards is having the three alerts above switched on.
I deleted the instance - why is it still billing?
Because volumes, snapshots, addresses and load balancers are independent resources that do not disappear with an instance. This is the single most common misunderstanding. Open the relevant consoles, sort by unattached or oldest, and it usually takes minutes to find.
How do I stop this happening again?
Three things: enable budgets and anomaly detection so you find out early, tag resources so you can attribute costs, and run a monthly orphan check over volumes, snapshots, addresses and idle load balancers. None of it saves money directly - but together they replace "hit by the bill once a month" with "anomaly handled within days".