Why AWS data transfer costs so much: six billing boundaries and how to cut each

AWS data transfer is not one charge but several, split by the path the bytes take: internet egress, cross-AZ, cross-region, plus any NAT gateway in the way. The same two instances in one zone are free over private IP - and billed in both directions over public IP.

2026-10-11

AWS data transfer is not one charge but several, split by the path the bytes take: internet egress, cross-AZ, cross-region, plus any NAT gateway in the way. The same two instances in one zone are free over private IP - and billed in both directions over public IP.

Data transfer is the hardest AWS cost to keep under control. Unlike an instance, it has no single obvious unit price and quantity - each byte is billed according to which path it took.

That produces a genuinely counter-intuitive result: two instances in the same availability zone move data for free over private addresses, and are billed per GB over public addresses - even though the physical route may be identical.

This page takes apart how many different transfer charges actually exist, and what to do about each. Finding out which resource is responsible is covered separately in why your AWS bill jumped and is not repeated here.

The mental model: you pay for the path, not the distance

In one line: AWS charges for the path, not the distance. The same bytes crossing inside one zone over private IP cost nothing; routed out through a NAT gateway they attract three overlapping charges. Changing the path beats changing the volume.

With that model, the question "why am I charged for traffic inside one region" answers itself - not because it moved, but because you put it on a path that is metered.

Six billing boundaries at a glance

AWS splits transfer by network location into three categories (egress to the internet, cross-AZ within a region, and cross-region), and adds the processing charges of the services sitting on the path. Together that is six boundaries:

BoundaryWhat triggers itHow it is billed
1 Egress to the internetResources in a region sending data out to the public internetPer GB, with a monthly free allowance
2 Cross-AZ in one regionTwo availability zones in the same region exchanging dataCharged in each direction
3 Cross-regionData moving from one region to anotherPer GB, billed by source region only
4 NAT gatewayTraffic from a private subnet routed out through NATData processing, both directions, on top of the charges above
5 Transit GatewaySeveral VPCs connected through a transit gatewayData processing, even for same-region traffic
6 Public IPv4 addressCommunicating over a public or elastic IP, including inside one VPCCharged in each direction

Note what boundaries 4, 5 and 6 have in common: they are not transfer rates but surcharges for the route you chose. That is exactly why they get missed - on the bill they are spread across different services and do not look like one thing.

Boundary one: egress to the internet

The most expensive and best-known item: resources in a region sending data to the public internet, billed per GB, with the rate stepping down as volume rises.

The pricing page contains one useful detail that is rarely repeated:

  • There is a monthly free egress allowance, aggregated across all AWS services and regions (China Regions and GovCloud excluded) - it is not granted separately per service or per region.
  • Billing is by source region: whichever region the data leaves from sets the rate, and the receiving region does not charge again.
  • Very large egress users can approach AWS about rates - the official channel is authoritative.

For anything public-facing, the bulk of this is usually static assets and downloads, which is why handing that to CloudFront is the most direct fix (see fix three below).

Boundary two: across availability zones in one region

This is the section worth remembering, because it contradicts most people intuition: inside a single region, data moving between two availability zones is charged - in each direction.

Crucially, the documentation is very specific about what counts as free:

Case within one regionCharged?
Same zone, communicating over private IPFree
Same zone, communicating over public / elastic IPCharged (each direction)
Across zones (private or public IP)Charged (each direction)
Same region, EC2 to S3 / DynamoDB / SQS / ECR and similar, directlyFree
But routed through NAT gateway / Transit Gateway / PrivateLink endpointThose services add their own processing charge

⛔ The contrast between the first two rows is the counter-intuitive core of this page: same pair of resources, same zone - the only difference is whether you reach the peer over a private address or a public one, and the public route is billed per GB in both directions. It is not a distance charge, it is a path charge. Plenty of teams habitually connect to their own databases and caches over public endpoints, generating the charge for no functional benefit whatsoever.

One more trap: multi-AZ deployment is the recommended high-availability pattern, and the steady traffic across zones is billed. High availability and transfer cost require an explicit trade-off (see fix five).

A useful exception: Application and Classic Load Balancers carry no cross-AZ charge, while a Network Load Balancer does charge for cross-AZ traffic to targets - worth confirming if your architecture uses an NLB with cross-zone load balancing enabled. Official pricing is authoritative.

Boundary three: across regions

Cross-region transfer costs more than cross-AZ, and the rate varies by region pair. It rarely hurts in one-off transfers and always hurts in continuous replication:

  • Cross-region database replication: as long as the replica exists, replication traffic keeps being generated and billed.
  • Cross-region object storage replication: same shape - more data and more churn means more ongoing cost.
  • Multi-region active architectures: every synchronising region pair adds its own stream.

The right question is not "do we need disaster recovery" but "does this workload actually need to fail over across regions". If you only need to survive a data-centre failure, multi-AZ within one region usually suffices - and the cost differs by an order of magnitude.

Cross-region traffic is also billed by source region only (the destination does not charge again), which simplifies estimation: you only need to know where data leaves from.

Boundaries four to six: NAT gateway, Transit Gateway, public IPv4

These three are not transfer rates but surcharges on the path, and they are the easiest part of the bill to miss - they are filed under different services and do not look related.

  • NAT gateway: billed on data processed, in both directions. Its classic waste case is a private-subnet instance reaching S3 or DynamoDB: the traffic leaves the VPC and comes back, so you pay NAT processing on top of egress. There is a free fix for exactly this (see fix one).
  • Transit Gateway: used to connect many VPCs, but it carries a data processing charge even for same-region traffic. For a handful of VPCs, direct peering is cheaper; a transit gateway earns its cost once the number of connections becomes unmanageable.
  • Public IPv4 addresses: AWS has stated that all public IPv4 addresses are now charged (effective February 2024). That lands hard on the habit of attaching a public IP to every instance - most of them do not need one; they need to be reachable by a load balancer, or simply to sit in a private subnet.

A self-check question: does this instance actually need a public address? If it only receives internal traffic inside a private subnet, a public IPv4 is pure additional cost. Moving from "public IP by default" to "public IP only when required" is often the cleanest subtraction available.

Five fixes, ranked by what they are worth

Ordered by effort against saving; the first two usually need no architecture change:

  1. Create a gateway VPC endpoint for S3 and DynamoDB. The best value available: it is free, and it removes the single most common waste - private-subnet traffic to S3 routed through a NAT gateway. Once done, that traffic stops traversing NAT, so neither the processing charge nor the egress charge applies.
  2. Check whether your application reaches same-VPC resources over public endpoints. Databases, caches, internal services - if the connection string uses a public address or an elastic IP, switch it to a private DNS name. Zero cost, zero risk, immediate effect (row 2 of boundary two).
  3. Serve static content and API responses through CloudFront. Three effects stack: S3 to CloudFront transfer is free, CloudFront own egress rate is lower than direct egress, and CloudFront has its own monthly free egress allowance. But note the precondition: with a low cache hit rate (bad cache rules, frequent invalidation) origin fetches still bill at full rate - the saving comes from cache hits, not from attaching CloudFront.
  4. Turn on compression. Text responses (JSON, HTML, JS) typically shrink by 60-80%, and every per-GB rate falls proportionally. A configuration change, not an architecture change.
  5. Keep your chattiest services in one availability zone. For services calling each other constantly - not occasionally - place them in the same zone and reserve cross-AZ for failover rather than everyday traffic. The cost is a re-think of the availability design, which is why this one is last: it is not a free win.

One prerequisite: tag your resources first. Without tags you will see a transfer charge and not know which environment or team produced it - and no fix can be aimed at anything. All five fixes above concern transfer only; the compute, storage and database side is in AWS billing: six actions that actually work.

FAQ

Is data transfer into AWS charged?

No. Ingress is free - resources on the public internet sending data into AWS incur no charge. Every billable item lives on the "going out" or "going the long way round" side, which rules out a lot of guessing immediately.

Why am I charged for traffic between machines in the same region?

Two cases: you crossed availability zones (charged in each direction, as the documentation states), or you are in the same zone but communicating over public / elastic IPs - the same pair of resources over private IPs is free. That second one is worth auditing in your code.

I already have the free allowance - why is there still a charge?

Because the free allowance covers internet egress only, and it is aggregated across all services and regions rather than granted per service, and it does not apply in the China Regions or GovCloud. Cross-AZ, cross-region and NAT processing charges do not draw on it.

What share of the bill should transfer be?

Third-party surveys put typical web and API workloads at roughly 6-12%, with data-heavy, multi-region or streaming workloads above 20% being normal (those ranges are industry observation, not official figures - use them for scale only). If your share is well above comparable workloads, the problem is usually not the traffic but the path - go back to boundaries two and four.

How do I find out which resource is transferring?

Two steps: group by usage type in Cost Explorer (egress, cross-AZ and NAT processing appear as distinct entries), then use VPC Flow Logs to attribute traffic to specific resources and zone pairs. The full workflow is in why your AWS bill jumped.

Do other cloud providers charge the same way?

Transfer is a shared cost item across all five, but the mechanics and the relief differ - some bundle generous egress into the product (lightweight plans usually include a traffic package), and some pass margin through a channel. All five compared in cloud discount mechanisms compared. If what you want is to lower what you actually pay without changing architecture, that is a different layer - see AWS discounts and reseller pricing.

Want to price this for your own usage?

Tell us your region and spec — an engineer will size it and quote. We accept USDT TRC-20.

Top up now