The single biggest mystery bucket on most bills — internet egress, cross-AZ, NAT gateways, and the region-code grammar behind all of it.
DataTransfer-Out-BytesAmazon EC2
Internet data transfer out
You are being charged per gigabyte for data leaving an AWS region to the public internet.
This is the single most common line item on almost every AWS bill: any response an EC2 instance, load balancer, or API sends back to a browser, mobile app, or external API counts as egress. It often shows up bundled under "EC2-Other" in Cost Explorer even when the traffic originated from another service that routes through EC2-managed infrastructure.
Spikes usually trace to a new public-facing feature (video/image delivery, large API payloads, backups pushed to an external destination), a bot or scraping wave hitting an unprotected endpoint, or serving large static assets directly instead of through a CDN.
How to cut it
- Put CloudFront (or another CDN) in front of anything served repeatedly to the public internet — CDN egress pricing is lower than direct-to-internet, and cached hits avoid origin egress entirely.
- Compress payloads (gzip/brotli) and move large downloadable files to S3 with appropriate storage/lifecycle tiers rather than serving from compute instances.
- Check for unintended public exposure (an open bucket, an unauthenticated endpoint) if the increase isn't tied to a known feature launch.
- Track usage against the account-wide free-tier allotment and the volume tiers below it so pricing assumptions match the actual tier.
$0.09 per GB (first 10 TB/month tier) — us-east-1, applies after the AWS-wide free tier; as of 2026-07
Source: AWS docs →USE1-USW2-AWS-Out-BytesAmazon EC2
Inter-region data transfer
You are being charged for data sent from one AWS region (here, us-east-1) to a different AWS region (here, us-west-2).
This appears whenever resources in different regions talk to each other: cross-region database replication or read replicas, multi-region S3 replication, a service in one region calling an API hosted in another, or disaster-recovery jobs.
It's confusing because AWS emits two line items for every transfer — a "{Source}-{Dest}-AWS-Out-Bytes" on the source side and a "{Dest}-{Source}-AWS-In-Bytes" on the destination side — but only the outbound side from the source region actually carries a charge; the inbound side is $0.
How to cut it
- Co-locate chatty services and their data stores in the same region wherever latency or compliance requirements allow.
- Use cross-region replication and read replicas deliberately (for DR/compliance), not as a default multi-region pattern, since every byte is billed on the sending side.
- For multi-region active-active architectures, weigh whether a global accelerator, private connectivity, or regional caching reduces total cross-region volume.
- Group by Usage type in Cost Explorer to see exactly which region pair is generating the charge before optimizing.
Source: AWS docs →DataTransfer-Regional-BytesAmazon EC2
Cross-AZ (regional) data transfer
You are being charged for data moving between Availability Zones within the same AWS region — billed on both the sending and the receiving side.
Same-AZ traffic over private IPs is free, but the moment two communicating resources land in different AZs, every byte is billed twice: once as the sender's outbound leg and once as the receiver's inbound leg.
Common triggers: an auto-scaled fleet or Kubernetes cluster spreading instances across AZs for high availability, a NAT gateway that exists in only one AZ while resources run in others, or chatty microservice/service-mesh traffic that isn't AZ-aware.
How to cut it
- Keep a NAT gateway (or gateway endpoint) in every AZ you use so traffic doesn't cross AZ boundaries just to reach the internet or an AWS service.
- Make AZ-aware routing/affinity a first-class concern in service mesh or load-balancer configuration so requests prefer same-AZ targets.
- For chatty replicated/clustered workloads, weigh the availability benefit of spreading across AZs against the steady-state cross-AZ transfer cost.
- Use flow logs alongside Cost Explorer's regional-transfer totals to identify which resource pairs are generating the volume — the billing data alone won't show you that.
$0.01 per GB, in each direction — us-east-1; billed as two separate $0.01/GB charges (in + out) for each transfer; as of 2026-07
Source: AWS docs →NatGateway-BytesAmazon VPC
NAT gateway data processing
You are being charged per gigabyte for every byte that passes through your NAT gateway, on top of its flat hourly uptime charge and on top of any standard data-transfer charge the traffic would incur anyway.
NAT gateways are the default egress path for private-subnet resources, so anything a private instance, a task, or a function does over the internet — pulling container images, calling third-party APIs, downloading OS/package updates — is metered here, often invisibly to the engineer who wrote the code.
The classic spike is container image pulls: registry layers, base OS images, and CI/CD artifact downloads routed through NAT can dwarf actual application traffic, especially in clusters with frequent deploys or aggressive auto-scaling.
How to cut it
- Add VPC gateway endpoints for S3 and DynamoDB (no hourly or per-GB charge) and interface endpoints for other AWS services so that traffic never touches the NAT gateway.
- Cache container base images and dependencies in-region rather than re-pulling from the internet on every deploy or scale event.
- Run one NAT gateway per AZ (not one shared gateway) to avoid stacking cross-AZ charges on top of NAT processing charges.
- For high-volume, latency-tolerant batch egress, evaluate whether a self-managed alternative is materially cheaper at your traffic volume.
$0.045 per GB processed — us-east-1; separate from the flat $0.045/hour NAT gateway uptime charge and from any standard data-transfer charge on the same bytes; as of 2026-07
Source: AWS docs →PublicIPv4:InUseAddressAmazon VPC
Public IPv4 address charge
You are being charged hourly for every public IPv4 address you hold — whether it's actively attached and serving traffic, or allocated but unattached and idle.
AWS began charging for all public IPv4 addresses on February 1, 2024 — previously only "extra"/idle Elastic IPs were charged. This now covers the default public IP on every internet-facing instance, every Elastic IP, NAT gateway public IPs, and public IPs on AWS-managed resources, not just Elastic IPs.
Bills spike when accounts accumulate unattached Elastic IPs left over from decommissioned instances, or when a large fleet of instances or NAT gateways each get their own public IP instead of sharing egress through fewer public endpoints.
How to cut it
- Release Elastic IPs that aren't attached to a running resource — they cost the same rate whether idle or in use, so idle ones are pure waste.
- Move private-subnet workloads behind a NAT gateway (shared public IP) instead of giving each instance its own public IP.
- Use a load balancer or CDN in front of a fleet instead of assigning public IPs to individual instances.
- Audit across accounts with Cost Explorer filtered to this usage type to find and reclaim unused allocations.
$0.005 per hour per address — us-east-1 (uniform across commercial AWS regions); identical whether the address is in-use or idle; as of 2026-07
Source: AWS docs →VpcEndpoint-BytesAmazon VPC
VPC interface endpoint (PrivateLink)
You are being charged an hourly fee per endpoint per Availability Zone, plus a per-gigabyte fee for data processed through an interface VPC endpoint (AWS PrivateLink).
This appears when you've deliberately added interface endpoints to avoid NAT gateway or internet routing for AWS-service traffic, or when a third-party product exposes itself via PrivateLink.
It surprises people two ways: the endpoint itself has an always-on hourly cost per AZ even at zero traffic, and teams sometimes deploy endpoints redundantly (one per AZ per service, per account) without realizing the hourly costs multiply.
How to cut it
- Prefer gateway endpoints (S3, DynamoDB), which have no hourly or per-GB charge, over interface endpoints when the target service supports both.
- Consolidate interface endpoints centrally in a shared-services VPC instead of duplicating the same endpoint in every account/VPC.
- Remove endpoints for services no longer in active use — the hourly charge accrues regardless of traffic.
- Compare the endpoint's hourly + per-GB cost against the NAT gateway cost it replaces; at low traffic volumes a NAT gateway can occasionally be cheaper than several redundant endpoints.
Source: AWS docs →TransitGateway-BytesAWS Transit Gateway
Transit Gateway attachment and data processing
You are being charged an hourly fee for each attachment (VPC, VPN, Direct Connect, peering) connected to your Transit Gateway, plus a per-gigabyte fee for data processed through it.
Transit Gateway is the common hub-and-spoke pattern for connecting many VPCs, accounts, and on-prem networks, so its cost scales with both how many VPCs you've attached (hourly, per attachment) and how much traffic actually flows through the hub (per GB).
Costs balloon in large multi-account organizations as more accounts/VPCs are onboarded to a shared Transit Gateway, or when high-volume, chatty services route large data volumes through the hub instead of communicating more directly.
How to cut it
- Use cost allocation tags on Transit Gateway attachments to see which team, account, or workload is driving hourly and data-processing charges.
- For very high-volume point-to-point paths between two VPCs, consider direct VPC peering (no per-GB processing fee) instead of routing that traffic through Transit Gateway.
- Remove attachments for decommissioned VPCs/accounts — the hourly charge continues until the attachment is explicitly deleted.
- Right-size the topology: not every VPC needs a Transit Gateway attachment if it only talks to one or two other VPCs.
Source: AWS docs →LoadBalancerUsageElastic Load Balancing
Load balancer hourly usage and LCU charge
You are being charged an hourly rate for each load balancer provisioned, plus a rate per Load Balancer Capacity Unit (LCU) consumed — LCUs are driven by whichever dimension (new connections, active connections, processed bytes, or rule evaluations) is highest that hour, not by a simple sum.
The flat hourly charge is predictable, but LCUs are the confusing part: AWS bills on the single highest-consuming dimension per hour, so a spike in new-connection rate or in processed bytes can drive cost up even if the other dimensions look normal.
Bills also climb simply from running more load balancers than needed — one per microservice or environment instead of consolidating with listener rules or path-based routing on shared load balancers.
How to cut it
- Consolidate multiple services behind fewer load balancers using host- or path-based routing rules instead of provisioning one per service.
- Investigate which LCU dimension is driving cost via CloudWatch metrics rather than assuming it's raw traffic volume.
- Tune client connection behavior (keep-alives, connection pooling) to avoid unnecessary new-connection churn.
- Delete idle/unused load balancers left over from decommissioned environments — the hourly charge accrues regardless of traffic.
Source: AWS docs →US-DataTransfer-Out-BytesAmazon CloudFront
CloudFront data transfer and requests
You are being charged per gigabyte for content CloudFront serves from its edge locations to end users, plus a per-10,000-requests charge, with rates varying by the edge-location group (US, EU, AP, and so on) that served the request.
This looks similar to plain internet egress on the bill but is a distinct, usually cheaper, product line keyed off the edge location that answered the request rather than the origin's AWS region — so the prefix here is a broad geography code, not the fine-grained region codes used elsewhere.
Costs climb with cache-miss rate (uncacheable or short-TTL dynamic content forces more origin fetches), high request-per-second traffic from bots or scrapers, and serving traffic from higher-cost edge-location groups rather than cheaper tiers.
How to cut it
- Increase cache hit ratio with longer TTLs and cache keys that don't over-fragment the cache.
- Use a price-class restriction to serve only from lower-cost edge-location regions if global reach isn't required.
- Enable compression and right-size assets at origin to reduce bytes served per request.
- Separate cacheable GET/HEAD traffic from proxied write traffic in your monitoring, since proxied requests to origin can't benefit from caching.
Source: AWS docs →