An AWS bill that jumped is almost always one or two line items, not a general drift — and Cost Explorer can name them in under an hour. The sequence is: compare this month to last month grouped by service, drill the mover down to usage type, switch to daily granularity to find the day it started, then match that date against what changed — a deploy, a new workload, a leak, or a retired discount. Resist the urge to start turning things off before you know which line item moved.
What’s happening
An AWS invoice is thousands of metered line items rolled up per service. When the total jumps, one of a short list of things happened: a workload scaled (more instance-hours, more requests), a data path got expensive (NAT Gateway processing, inter-AZ or egress transfer, S3 API storms), storage accumulated past a threshold you notice (snapshots, logs, versioned buckets), a commitment expired (Savings Plan or RI lapsed and the same usage re-priced at on-demand), or something was created and forgotten (a second environment, an idle GPU instance, a load test left running). Compromised credentials mining crypto produce the same signature as a scaled workload — large EC2 or SageMaker charges in regions you do not use — so the triage below checks regions explicitly.
Two billing mechanics matter here. First, Cost Explorer data lags roughly 24 hours, so today’s leak shows up tomorrow. Second, unblended cost shows commitment purchases as spikes on the purchase date; if someone bought an upfront RI, the “spike” may be the discount, not a problem — check the amortized view before panicking.
What to check first
- Which service moved? One grouped comparison answers this in two minutes.
- When did it start? Daily granularity turns “this month is high” into “it started June 14th.”
- Which region? Charges in regions you do not operate in point to a leak or a compromise.
- Did a commitment expire? Same usage, higher rate, no deploy to blame.
- Is it one account? If you run Organizations, group by linked account first.
How to verify
Console first: Billing and Cost Management > Cost Explorer, date range covering last month and this month, granularity Monthly, Group by: Service. The mover is usually obvious. Then filter to that service and switch Group by: Usage Type — usage type names the mechanism (NatGateway-Bytes is data processing, USW2-BoxUsage:m5.xlarge is instance-hours in Oregon, TimedStorage-ByteHrs is S3 storage). Same thing from the CLI:
# Month-over-month by service — find the mover
aws ce get-cost-and-usage \
--time-period Start=2026-05-01,End=2026-07-01 \
--granularity MONTHLY \
--metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICE
# Drill the mover down to usage type, daily — find the start date
aws ce get-cost-and-usage \
--time-period Start=2026-06-01,End=2026-07-01 \
--granularity DAILY \
--metrics UnblendedCost \
--filter '{"Dimensions":{"Key":"SERVICE","Values":["Amazon Elastic Compute Cloud - Compute"]}}' \
--group-by Type=DIMENSION,Key=USAGE_TYPE
# Anything running in regions you do not use?
aws ce get-cost-and-usage \
--time-period Start=2026-06-01,End=2026-07-01 \
--granularity MONTHLY \
--metrics UnblendedCost \
--group-by Type=DIMENSION,Key=REGION
For the start date, cross-reference CloudTrail: CloudTrail > Event history, filtered to the day the cost line bent, tells you what was launched and by whom.
The runbook
- Group by service, month over month (10 minutes). One service up sharply is a lead; everything up proportionally suggests traffic growth or an expired discount, not a leak.
- Drill to usage type (10 minutes). This separates “more instances” from “more data processing” from “more storage” — three different fixes. Data-transfer and NAT usage types are where the surprises usually live; the egress mechanics are covered in NAT Gateway vs NAT instance.
- Switch to daily granularity (5 minutes). Find the exact day the line bent. A step change means something launched or broke; a ramp means accumulation (storage, logs) or organic growth.
- Match the date to a change (15 minutes). Deploy log, CloudTrail event history, team chat. A load test, a new environment, a retry storm after a bad deploy, a cron gone rogue — the date almost always names the culprit.
- Check commitments if nothing changed (10 minutes). Billing and Cost Management > Savings Plans and the RI pages show expiry dates. An expired commitment re-prices the same usage at on-demand — the fix is a renewal decision, covered in RIs, Savings Plans, Spot, and on-demand.
- Check for compromise if the region or service is foreign (10 minutes). Large compute in unused regions, SageMaker or ECS you never enabled: rotate the exposed keys immediately, terminate the resources, then open a case — AWS Support handles compromised-account remediation and, case by case, billing adjustment requests for verified compromises.
When this is the wrong move
If the bill is high but has been high for months, this is not a spike triage — it is a structural cost problem, and the lever-by-lever reduction work is a different exercise. And if the spike traces to real customer growth, the answer is unit economics and commitment coverage, not cost-cutting; do not throttle a growing product to flatten a graph.
Common mistakes
- Turning things off before identifying the line item. You risk an outage and the bill stays high because you guessed wrong.
- Reading unblended cost during a commitment purchase month. The upfront charge looks like a spike; the amortized view is the honest one.
- Ignoring regions. Cost Explorer defaults show all regions, but people mentally filter to the one they use — the leak is often elsewhere.
- Stopping at the service level. “EC2 went up” is not a diagnosis; the usage type is.
Prevention
- Turn on Cost Anomaly Detection — it exists precisely so this triage happens on day two, not at invoice time.
- Set AWS Budgets alerts at 80% actual and 100% forecast so mid-month overruns page someone.
- Tag workloads so a spike maps to an owner in one click.
- Put commitment expiry dates in the team calendar a month ahead.
- Review the AWS Cost Management docs once — knowing the difference between unblended and amortized cost prevents two of the false alarms above.
One focused hour finds the cause of nearly every bill spike, and the same hour repeated monthly keeps the next one from surprising you. If nobody on your team truly owns the AWS environment end to end, that is the root of most of these problems — Stack Harbor runs AWS accounts daily under AWS Operations, and you can book an AWS review.