Free lesson · AWS Fundamentals
How AWS pricing actually works - the four cost levers
The Four Levers
AWS sells hundreds of services with hundreds of pricing pages, and the surface looks impenetrable. It is not. Almost every charge on an AWS bill falls into one of four categories:
- Compute time - something ran for a duration. EC2 instance-hours, Lambda GB-seconds, Fargate vCPU-seconds, RDS instance-hours.
- Storage volume × duration - something occupied space for a period. GB-months of S3, EBS, EFS, RDS storage, snapshots.
- Data transfer - bytes moved across a boundary that AWS charges for.
- Requests and operations - a countable API-level action. S3 PUTs, Lambda invocations, DynamoDB reads and writes, API Gateway calls, KMS decrypt operations.
When you look at an unfamiliar service's pricing page, sort what you see into these four buckets and the model becomes legible immediately. When you get a surprising bill, the surprise is almost always in lever 3 or lever 4 - the two that scale with behaviour rather than with provisioned size, and therefore the two nobody estimates correctly.
Lever 3 Is The One That Bites: Data Transfer
Data transfer pricing is the most consequential thing in this topic. It is charged based on the boundary a byte crosses.
| Movement | Charged? |
|---|---|
| Internet → AWS (inbound) | Free |
| AWS → Internet (outbound) | Charged, tiered, most expensive rate |
| Within the same AZ, using private IPv4 | Free |
| Within the same AZ, using public IP or Elastic IP | Charged |
| Between AZs in the same Region | Charged - historically in both directions |
| Between Regions | Charged, rate varies by Region pair |
| Through a NAT Gateway | Charged per GB processed, on top of any transfer charge |
| Through a VPC Gateway Endpoint (S3, DynamoDB) | No endpoint charge |
| Through a VPC Interface Endpoint (PrivateLink) | Hourly charge per endpoint per AZ, plus per GB |
| CloudFront → Internet | Charged, but usually cheaper than direct egress |
graph LR
I[Internet] -->|free| ALB[Load Balancer]
ALB -->|charged if cross-AZ| APP[App Tier]
APP -->|charged if cross-AZ| DB[(Database)]
APP -->|per-GB processing charge| NAT[NAT Gateway]
NAT -->|egress charge| I2[Internet]
APP -->|no endpoint charge| GE[Gateway Endpoint]
GE --> S3[(S3)]
ALB -->|egress charge| I
This diagram traces where charges accrue along a request path. Traffic entering from the internet to a load balancer is free. Traffic from the load balancer to the application tier is charged if it crosses an Availability Zone boundary, as is traffic from the application tier to the database. Traffic from the application tier out through a NAT Gateway incurs a per-gigabyte processing charge plus an egress charge to the internet. Traffic from the application tier to S3 through a Gateway Endpoint incurs no endpoint charge. Traffic returning from the load balancer to the internet incurs an egress charge.
Warning: The NAT Gateway is the single most common source of "why is our bill this high." It charges an hourly rate per gateway and a per-GB processing fee on everything passing through - including traffic to AWS services in the same Region. A workload pulling container images or writing to S3 through NAT is paying for bytes that could travel free through a Gateway Endpoint. Check this before optimising anything else.
Commitment Models
Compute is where the pricing model offers you real choices, and the choice is a bet about how predictable your usage is.
| Model | Discount | Commitment | Interruption risk |
|---|---|---|---|
| On-Demand | none (baseline) | none | none |
| Savings Plans | substantial | 1 or 3 years of $/hour spend | none |
| Reserved Instances | substantial | 1 or 3 years of specific capacity | none |
| Spot | largest | none | AWS can reclaim with short notice |
The practical guidance:
- Savings Plans over Reserved Instances for most new commitments. Savings Plans commit to a dollar-per-hour spend rather than a specific instance type, which means they keep applying when you change instance families or move from EC2 to Fargate.
- Spot for anything that can be interrupted and restarted - batch, CI runners, stateless web tiers behind an ASG with a mixed instances policy, data processing with checkpointing.
- Commit to your floor, not your average. Cover the baseline you will definitely run with Savings Plans; let the peak run On-Demand or Spot. Over-committing is worse than under-committing because unused commitment is pure waste.
Tip: Savings Plans and Reserved Instances share across accounts in an AWS Organization with consolidated billing enabled. An unused commitment in one account automatically applies to matching usage in another. This is one of the strongest practical arguments for consolidated billing and a reason not to fragment your organisation across multiple payer accounts.
The Free Tier
Three distinct kinds, frequently confused:
- 12-month free tier - expires 12 months after account creation. Includes the well-known allowances such as a small EC2 instance for a set number of hours per month and a quantity of S3 storage.
- Always free - does not expire. Includes a monthly Lambda request and compute allowance, DynamoDB storage, CloudWatch basics, and others.
- Trials - short-term, service-specific, usually starting on first use of that service.
Important: The free tier is per account, not per person, and it does not stop charges - it discounts them. Exceeding it produces a real bill silently. Set a Budget alert at a low threshold on day one of any new account. The most common expensive accident is leaving a load balancer, a NAT Gateway, an unattached Elastic IP, or a provisioned database running after an experiment; none of these are free-tier covered at typical usage.
Reading An Unfamiliar Pricing Page
Three examples showing how the four levers compose:
S3 - storage GB-month (varies by class) + requests by type (PUT costs more than GET) + retrieval fees on colder classes + data transfer out. A workload with tiny objects and heavy request volume can spend more on requests than on storage.
Lambda - requests + GB-seconds (memory allocated × duration). Allocating more memory raises the per-millisecond rate but often lowers total cost, because CPU scales with memory and the function finishes sooner. This is not intuitive and is worth measuring rather than assuming.
DynamoDB - provisioned capacity units per hour, or on-demand per request + storage GB-month + optional features (streams, backups, global tables replication). On-demand costs more per request but eliminates capacity planning; provisioned with autoscaling is cheaper at steady high volume.
Common Failure Modes
Warning: Cross-AZ chatter in a microservice mesh. Services calling each other randomly across three AZs can generate transfer charges rivalling the compute bill. Topology-aware routing keeps a request inside one AZ once it enters.
CloudWatch Logs ingestion. Charged per GB ingested, and verbose debug logging left on in production is a recurring surprise. Retention settings control storage cost, not ingestion cost - you must reduce what you emit.
Idle provisioned resources. Load balancers, NAT Gateways, provisioned RDS, unattached Elastic IPs, and unattached EBS volumes all charge whether or not anything uses them.
Snapshot accumulation. EBS and RDS snapshots are incremental but never expire on their own. Years of automated snapshots become a real line item.
Under-sized Lambda memory. Optimising for the lowest memory setting frequently increases total cost and always increases latency.
Why This Matters In An Interview
Interview: In certification exams, the phrases "most cost-effective" and "least operational overhead" are the qualifiers that decide the answer. Two options will both be technically correct; the qualifier selects between them. Train yourself to read the qualifier before the options.
In system design interviews, naming a cost implication unprompted is a strong senior signal. "I'd put a Gateway Endpoint here so the S3 traffic doesn't go through NAT" or "this is chatty across AZs, so I'd keep the request path zone-local" tells the interviewer you have operated a system, not just designed one.
Common follow-ups:
- "How would you reduce this architecture's cost by 30%?" → Work the levers in order: eliminate idle resources, fix data transfer paths, right-size compute, then commit to Savings Plans on the remaining baseline. Do not open with Spot.
- "Serverless is cheaper, right?" → At low and spiky volume, usually. At sustained high volume, Lambda frequently costs more than an equivalent always-on container fleet. The honest answer names the crossover.
- "Where would you look first on a surprise bill?" → Cost Explorer grouped by service, then by usage type. Usage type is where NAT processing and data transfer become visible; service-level grouping hides them.
Practice
Exercise: Starter. Open Cost Explorer on any account and group by usage type rather than by service. Identify every line that is data transfer or NAT processing.
Intermediate. Take a Lambda function you control and measure cost and duration at three memory settings. Find the setting that minimises total cost, and note whether it is the smallest one.
Advanced. Model the monthly cost of a three-tier application at 100 requests/second and again at 10,000 requests/second, using both a serverless design and a container design. Identify the crossover point and state which assumption in your model is least reliable.
Related Topics
- Module 13 - Cost, FinOps & Optimisation: the full treatment, including the Cost and Usage Report and Savings Plans analysis
- Module 03 - Networking: VPC Endpoints, NAT Gateway, CloudFront
- Module 04 - Compute: purchase options and Spot