AWS Cost Explorer
The tool for answering “why did the bill go up”. It reports and forecasts spend; it does not reduce it. What makes it useful — or useless — is decided months earlier, by whether anything is tagged.
The drill-down that answers the question
Cost questions are answered by narrowing, in this order:
- Group by service. Which service moved.
- Group by usage type. What in that service moved —
DataTransfer-Outis a different problem fromBoxUsage. - Filter by tag. Whose it is.
- Switch to daily granularity. When it started, which usually names the deploy.
import boto3
ce = boto3.client("ce")
resp = ce.get_cost_and_usage(
TimePeriod={
"Start": "2026-07-01", "End": "2026-08-01"
},
Granularity="DAILY",
Metrics=["UnblendedCost"],
GroupBy=[
{"Type": "DIMENSION", "Key": "SERVICE"},
{"Type": "TAG", "Key": "team"},
],
)Two GroupBy keys is the API maximum, which is why the workflow above is
iterative rather than one query.
The usual culprits
| Symptom | Look at |
|---|---|
| Cost with no traffic | idle NAT, ALBs, unattached EBS |
| Sudden step change | a deploy, or a new region |
| Steady creep | log ingestion, snapshot growth |
| Cost with no owner | untagged, or a forgotten account |
Data transfer is the perennial surprise: NAT Gateway processing charges and cross-AZ traffic are billed per GB and invisible in any per-instance view. A chatty service split across AZs pays for every hop.
Which cost metric you pick changes the number
| Metric | Shows |
|---|---|
| Unblended | what each account was actually charged |
| Blended | averaged rate across the organisation |
| Amortised | reservations spread over their term |
| Net | after discounts and credits |
Amortised is the honest one for trend analysis: it spreads an upfront Savings Plan or Reserved Instance payment across the period it covers, instead of showing a spike in the month you bought it and artificial savings after. Reporting unblended cost to a finance team that bought a three-year commitment produces a conversation you do not want.
Tags are a governance problem, not a reporting one
Cost allocation only works if resources carry tags, and:
Gotcha: activating a cost allocation tag is not retroactive. Cost data before activation is not re-tagged, so a tag you switch on today gives you attribution starting today. This is why “we’ll tag it later” costs you the historical analysis permanently.
Practical policy: a small, mandatory set (team, env, service,
cost-center), enforced with Service Control Policies or Config rules rather
than documentation, and activated in the billing console on day one.
Where tags cannot reach — shared clusters, a NAT gateway serving everyone — split-cost allocation and separate accounts per team are the tools. Account-per-team is the blunt version and by far the easiest to attribute.
Budgets and anomaly detection do different jobs
Budgets a number you chose, alerted on
Anomalies a change from the pattern, learnedBudgets catch planned overspend against a known figure and can act — trigger an SNS alert, or an action that applies a restrictive IAM policy. Anomaly detection catches the spike nobody budgeted for, which is usually the one that matters.
Set budgets on forecast as well as actual, or a month-end alert arrives after the money is gone.
Where the AI spend shows up
For an AI-facing team this is now often the fastest-growing line, and it is mostly Bedrock, SageMaker endpoints, and the storage and transfer behind a vector store.
The controls that work, in order of effect:
- Route by task complexity — a small model for classification and extraction, a frontier model for reasoning. This is the biggest lever and the expected senior answer.
- Cap output tokens. Output costs several times input, so a verbose response format is a recurring charge.
- Prompt caching for a long, stable system prompt or retrieved context.
- Right-size or scale to zero idle inference endpoints — a provisioned endpoint bills whether or not it serves a request.
- Per-tenant budgets, so one customer’s usage is visible before it is structural.
See Inference and serving for the mechanics behind routing and caching.
What Cost Explorer is not
- Not real-time. Data lags by up to 24 hours, so it will not catch a runaway in the hour it starts. Budgets with anomaly detection are the faster signal.
- Not detailed enough for chargeback at resource granularity — that is the Cost and Usage Report (CUR) in S3, queried with Athena.
- Not free at the API.
GetCostAndUsageis billed per request, which is worth knowing before wiring it into a dashboard that polls.
Related
Interview angle 6
- “How do you find out why the bill went up?” - Cost Explorer grouped by service, then by usage type, then filtered by tag. The usual answers are data transfer (especially NAT Gateway and cross-AZ traffic), unattached EBS volumes and idle load balancers, or a runaway log ingestion volume.
- “What makes cost attribution possible at all?” - a tagging policy enforced from day one, activated as cost allocation tags. Retrofitting tags does not retroactively split historical cost, which is why this is a governance question, not a reporting one.
- “Where does LLM spend show up and how do you control it?” - Bedrock and inference endpoints are usually the fastest-growing line. Control it with model routing (cheap model for simple requests), prompt caching, output token limits, and per-tenant budgets - not by turning down the frontier model everywhere. See Inference and serving.
- “Budgets or anomaly detection?” - both. Budgets catch planned overspend against a known figure; anomaly detection catches the unplanned spike you did not think to budget for.
- “Unblended, blended or amortised?” - amortised for trend analysis, because it spreads an upfront Savings Plan or RI payment across the term instead of showing a spike in the purchase month and false savings afterwards. Unblended is what each account was actually charged.
- “When is Cost Explorer the wrong tool?” - when you need resource-level chargeback or sub-day latency. That is the Cost and Usage Report in S3 queried with Athena, and budget alerts respectively.