How to Read Your AWS Bill: A Practical Guide to Understanding AWS Costs
Your AWS bill arrived and the total is higher than expected. You open it, see a wall of line items across 30 services, and close the tab. Sound familiar?
AWS billing is not intuitive. The console spreads cost data across multiple pages, uses terminology that differs from what you see in your day-to-day work, and buries some of the most expensive charges in generic categories like “data transfer.” This guide walks through every section of your AWS bill, explains the charges that catch people off guard, and shows you how to use Cost Explorer and the CLI to actually understand where your money goes.
Where to Find Your Bill
Log into the AWS Management Console and navigate to Billing and Cost Management. You can get there by clicking your account name in the top-right corner and selecting “Billing and Cost Management,” or by searching for “Billing” in the console search bar.
The Billing home page shows three things at a glance:
- Spend summary: What you spent last month, your month-to-date total, and a forecast for the current month.
- Month-to-date spend by service: A breakdown of your top services by cost.
- Cost trend: A multi-month chart showing whether your spending is going up or down.
For the actual invoice, click Bills in the left sidebar. This shows your charges organized by service, with expandable sections for each one.
Understanding Service-Level Charges
The Bills page groups charges by AWS service. Each service section expands to show the specific usage types that generated costs. Here is what a typical month might look like for a small production workload:
| Service | Monthly Cost | What Is Driving It |
|---|---|---|
| Amazon EC2 | $487.20 | 3 m6i.large instances running 24/7 |
| Amazon RDS | $312.45 | db.r6g.large Multi-AZ PostgreSQL |
| AWS Data Transfer | $89.30 | Cross-region replication + API responses |
| Amazon S3 | $34.12 | 2 TB standard storage + requests |
| Amazon CloudWatch | $28.50 | Custom metrics + log ingestion |
| NAT Gateway | $67.80 | Hourly charge + data processing |
| AWS Lambda | $4.20 | 2M invocations, 256 MB memory |
| Total | $1,023.57 |
Within each service, you will see line items broken down by usage type. For EC2, that means separate entries for compute hours, EBS volume storage, EBS IOPS, and snapshots. For S3, you will see storage, GET requests, PUT requests, and data retrieval separately.
The important thing to understand: AWS does not charge per “resource.” It charges per usage dimension. A single EC2 instance generates charges for compute, storage, network, and monitoring separately.
Data Transfer Costs: The Hidden Killer
Data transfer is the line item that surprises people the most. AWS charges for data leaving its network, data moving between regions, and even data moving between Availability Zones within the same region.
Here is a simplified breakdown of data transfer pricing:
| Transfer Type | Cost per GB |
|---|---|
| Data out to the internet (first 10 TB/month) | $0.09 |
| Data between AWS regions | $0.02 |
| Data between Availability Zones (same region) | $0.01 each direction |
| Data into AWS from the internet | Free |
| Data within the same Availability Zone (private IP) | Free |
The cross-AZ charge is particularly sneaky. If you run an application across three Availability Zones (as AWS recommends for high availability), every internal API call between services in different AZs costs $0.01/GB in each direction. For a microservices architecture doing significant inter-service communication, this adds up fast.
You can check your data transfer costs with the CLI:
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY \
--metrics "UnblendedCost" \
--filter '{"Dimensions":{"Key":"USAGE_TYPE_GROUP","Values":["EC2: Data Transfer - Internet (Out)","EC2: Data Transfer - Inter AZ","EC2: Data Transfer - Region to Region"]}}' \
--group-by Type=DIMENSION,Key=USAGE_TYPE_GROUP
Regional Pricing Differences
Not all AWS regions cost the same. The US regions (N. Virginia, Ohio, Oregon) are consistently the cheapest. Prices increase as you move to Europe, then Asia Pacific, with South America being the most expensive.
Here is a comparison using a t4g.large instance:
| Region | Hourly Cost | Monthly Cost (730 hrs) | Markup vs. US East |
|---|---|---|---|
| US East (N. Virginia) | $0.0672 | $49.06 | Baseline |
| EU (Ireland) | $0.0736 | $53.73 | +10% |
| Asia Pacific (Tokyo) | $0.0864 | $63.07 | +29% |
| South America (Sao Paulo) | $0.1072 | $78.26 | +60% |
S3 storage follows a similar pattern. Standard storage in N. Virginia costs $0.023/GB/month, while Sao Paulo charges $0.0405/GB/month, a 76% premium.
If your workload does not require low latency to a specific geography, running in US East or US West can save 10-60% depending on the service and target region.
Taxes and Credits on Your Bill
At the bottom of your bill, you will find two sections that affect your total:
Tax charges depend on your business location and local tax law. US customers may see state sales tax. EU customers see VAT. These appear as separate line items below the service charges.
Credits reduce your total. They show up as negative values. Common credit types include:
- AWS Activate credits (for startups)
- Enterprise Discount Program credits
- Support credits from service disruptions
- Promotional credits from events or programs
Credits are applied automatically, but they expire. Check the Credits page under Billing to see when yours run out.
Using Cost Explorer Effectively
Cost Explorer is the single most useful tool for understanding your AWS spending. You can access it from Billing and Cost Management by clicking Cost Explorer in the left sidebar.
Group by Service
Start with the default view: monthly costs grouped by service. This shows you which services are driving your bill. If one service dominates, click into it to investigate further.
Group by Usage Type
Once you identify an expensive service, switch the Group By to Usage Type. This reveals the specific charge dimensions. For example, grouping EC2 by usage type separates compute hours from EBS storage from data transfer, so you can see exactly which part of EC2 is expensive.
Filter by Tag
If you have cost allocation tags set up (more on that below), you can filter by tag to see costs for a specific project, environment, or team. Click Tag in the filter panel and select the tag key and value.
Daily vs. Monthly Granularity
Monthly granularity is good for trend analysis. Daily granularity is essential for finding spikes. If your bill jumped this month, switch to daily view and look for the day the increase started. That narrows your investigation significantly.
CLI Queries for Cost Explorer
You can query Cost Explorer programmatically. Here are three commands you will use regularly.
Get monthly costs by service:
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY \
--metrics "UnblendedCost" \
--group-by Type=DIMENSION,Key=SERVICE
Get daily costs for the current month:
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-03-22 \
--granularity DAILY \
--metrics "UnblendedCost"
Get costs filtered by a specific tag:
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY \
--metrics "UnblendedCost" \
--filter '{"Tags":{"Key":"Environment","Values":["production"]}}' \
--group-by Type=DIMENSION,Key=SERVICE
Note: each Cost Explorer API request costs $0.01. Running these queries a few times a month is negligible, but building a dashboard that polls every minute will add up.
Cost Allocation Tags: Why You Need Them
Without tags, Cost Explorer can only tell you “EC2 cost you $2,400 this month.” With tags, it can tell you “the staging environment cost $800, the production API cost $1,200, and the data pipeline cost $400.”
To use tags for billing:
- Tag your resources consistently. At minimum, use
Environment(production, staging, dev) andProjectorTeam. - Activate tags for billing. Go to Billing > Cost Allocation Tags and activate both AWS-generated tags and your user-defined tags.
- Wait 24 hours. Tags take up to 24 hours to appear in Cost Explorer after activation.
Tags only apply going forward. They do not retroactively categorize past spending. Start tagging today and your cost data gets more useful every month.
A practical tagging scheme:
| Tag Key | Example Values | Purpose |
|---|---|---|
| Environment | production, staging, dev | Separate env costs |
| Project | api-backend, data-pipeline, ml-training | Per-project attribution |
| Team | platform, data-eng, frontend | Team-level chargebacks |
| CostCenter | CC-1001, CC-1002 | Finance department mapping |
AWS Cost and Usage Report (CUR)
Cost Explorer is great for interactive analysis. For deeper analysis, programmatic queries, or historical reporting, you need the Cost and Usage Report.
CUR delivers a detailed CSV (or Parquet) file to an S3 bucket with every line item on your bill. Each row represents a single usage record with columns for the account, service, operation, resource ID, usage amount, cost, tags, and more.
Setting Up CUR with Athena
The most practical way to query CUR is through Amazon Athena:
- Go to Billing > Data Exports and create a new export.
- Select Parquet format (required for Athena integration).
- Point the export to a dedicated S3 bucket.
- Enable the Athena integration. AWS generates a CloudFormation template that sets up the Glue database and table automatically.
- Wait up to 24 hours for the first report delivery.
Once set up, you can run SQL queries against your billing data:
SELECT line_item_product_code,
SUM(line_item_unblended_cost) AS total_cost
FROM cur_database.cur_table
WHERE line_item_usage_start_date >= DATE '2026-03-01'
AND line_item_usage_start_date < DATE '2026-04-01'
GROUP BY line_item_product_code
ORDER BY total_cost DESC
LIMIT 10;
Always filter on line_item_usage_start_date. CUR data is partitioned by date, and Athena charges $5 per TB scanned. Without a date filter, you scan the entire dataset and pay more than you need to.
Billing Alerts and Budgets
Do not wait until the end of the month to discover a cost problem. Set up alerts on day one.
Option 1: CloudWatch Billing Alarm
This is the quickest setup. It triggers when your estimated charges exceed a threshold.
- Switch to the US East (N. Virginia) region. Billing metrics only exist in this region.
- Go to CloudWatch > Alarms > Create Alarm.
- Select the Billing > Total Estimated Charge metric.
- Set a static threshold (for example, $500).
- Configure an SNS topic to email you when the alarm fires.
Billing metrics update roughly every 6 hours, so this is not real-time. But it catches runaway costs before they become a disaster.
Option 2: AWS Budgets
Budgets are more flexible than CloudWatch alarms. They support forecasted spend alerts (warning you before you hit the threshold, not after), cost filters by service, tag, or account, automated actions like stopping EC2 instances when a budget is exceeded, and monthly, quarterly, or annual budget periods.
Create a zero-spend budget if you are on Free Tier. This alerts you the moment any charge appears. For production accounts, set budgets at 80% and 100% of your expected monthly spend.
aws budgets create-budget \
--account-id 123456789012 \
--budget '{
"BudgetName": "monthly-total",
"BudgetLimit": {"Amount": "1000", "Unit": "USD"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST"
}' \
--notifications-with-subscribers '[{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 80,
"ThresholdType": "PERCENTAGE"
},
"Subscribers": [{
"SubscriptionType": "EMAIL",
"Address": "[email protected]"
}]
}]'
Common Billing Surprises
These are the charges that catch teams off guard repeatedly.
NAT Gateway Data Processing
A NAT Gateway costs $0.045/hour ($32.85/month) just to exist. On top of that, AWS charges $0.045/GB for every byte that passes through it. If your private subnets route traffic to S3, ECR, or other AWS services through a NAT Gateway instead of using VPC endpoints, you are paying data processing fees for traffic that never leaves AWS.
A single NAT Gateway handling 500 GB/month of traffic to AWS services costs $32.85 (hourly) + $22.50 (data processing) = $55.35. Add cross-AZ transfer fees if your instances are in different AZs from the NAT Gateway, and you are looking at $60-70/month for a single gateway. Multiply by three AZs and it is $180+/month before any internet-bound traffic.
Fix: Create VPC endpoints for S3, DynamoDB, ECR, and other frequently accessed AWS services. Gateway endpoints for S3 and DynamoDB are free.
CloudWatch Logs Ingestion
CloudWatch charges $0.50/GB for log ingestion in US East. A verbose Lambda function logging full request/response bodies at 1,000 invocations per minute can generate 50+ GB/month in logs. That is $25/month from a single function, and most teams have dozens.
Fix: Set log levels appropriately. Use structured logging and avoid logging full payloads in production. Set retention policies so you are not storing (and paying for) logs forever.
Cross-AZ Data Transfer in ELB Architectures
When an Application Load Balancer routes traffic to targets in a different AZ, you pay $0.01/GB in each direction for cross-AZ transfer. For a service handling 1 TB/month of traffic, that is $20/month in cross-AZ fees alone, billed under EC2 data transfer rather than ELB.
Idle Resources in Forgotten Environments
That staging environment someone spun up three months ago? It is still running. The RDS instance for a proof-of-concept that was never cleaned up? Still billing. Idle resources are the most common source of waste, and they do not show up as a spike. They show up as a baseline that slowly creeps up.
Elastic IP Addresses
An Elastic IP attached to a running instance is free. An Elastic IP that is allocated but NOT attached to a running instance costs $0.005/hour ($3.65/month). Small per IP, but teams that allocate IPs during deployments and forget to release them can accumulate dozens.
Free Tier Tracking and Gotchas
AWS Free Tier covers a generous set of services for new accounts, but the gotchas are real.
The 12-month clock starts when you create the account, not when you start using a service. If you create an account in January and do not launch an EC2 instance until June, you only get 7 months of Free Tier EC2, not 12.
Free Tier limits are per account, not per resource. The 750 hours/month of t2.micro or t3.micro covers ONE instance running all month. Launch two and you are paying for the second one from hour one.
AWS does not notify you when trials expire. Short-term trials (like 60 days of Amazon Inspector or 12 months of RDS Free Tier) end silently. You start paying standard rates the next day.
Tracking your usage: Go to Billing > Free Tier in the console. This page shows your usage against Free Tier limits for each eligible service. Enable Free Tier usage alerts in Billing Preferences to get an email when you hit 85% of any limit.
The safest approach: set a zero-spend AWS Budget. If anything at all gets charged, you get an alert immediately.
Putting It All Together
Reading your AWS bill is not a one-time exercise. It is a monthly practice. Here is a practical routine:
- First of the month: Review last month’s bill. Compare to the previous month. Flag anything that grew more than 10%.
- Check Cost Explorer daily view for any spending spikes in the current month.
- Review your budgets to make sure alerts are still calibrated to your expected spend.
- Quarterly: Audit your tags. Make sure new resources are tagged. Check for untagged spend in Cost Explorer.
- Quarterly: Review your CUR data for per-resource costs. Find the individual resources costing you the most.
If running CLI commands and reviewing CUR data manually sounds tedious, that is because it is. CostPatrol automates the detection side of this. It scans your AWS account for the exact issues described in this guide, including idle resources, missing VPC endpoints, oversized instances, and unattached volumes, and surfaces them with estimated savings. A free scan takes minutes and covers the checks that would take hours to run manually.
The bill will always be complex. But once you know where to look and what the charges actually mean, it stops being a mystery and starts being a tool for making better infrastructure decisions.