Why this matters
AWS bills data transfer as separate line items, not one simple charge. You see internet egress, cross-AZ traffic, cross-region copies, NAT Gateway processing, Transit Gateway data processing, load balancer cross-zone traffic, and CloudFront origin fetches in different places. A workload can look cheap on compute and still cost money because it talks to a database in another zone or sends logs over NAT.
The hard part is attribution. A NAT Gateway is shared by several subnets. A Transit Gateway carries traffic for teams that never see the bill. Cross-AZ traffic between an app tier and a cache looks like normal request latency in application logs. Without tags and a cost and usage report, you cannot tell which change reduced spend or which workload caused it.
Reducing transfer costs is architecture work. Keep traffic local. Cache before it crosses a billed boundary. Pick the path that meets latency and recovery needs at the lowest transfer cost. Do not ban egress; find the crossings that add no value and remove them.
Before you start
Get a baseline before you change anything. Turn on the AWS Cost and Usage Report and deliver it to an S3 bucket. Query it with Athena or another tool to group line items by usage type, account, region, and resource. Cost Explorer is fine for a first look, but the CUR gives you the detail to prove a saving later.
Map accounts, VPCs, subnets, Availability Zones, peering links, Transit Gateway attachments, NAT Gateways, load balancers, and VPC endpoints. Note which workloads must stay multi-AZ, which need cross-region copies, and which have latency budgets. Ask owners before you move a database or turn off cross-zone load balancing.
Set cost allocation tags for application, environment, owner, and cost center. Tag shared network resources too, or put them in a shared services account. Decide how you will split NAT Gateway, Transit Gateway, and load balancer charges. If you skip that, a saving in one place becomes a cost shift in another.
How to do it
Start with the biggest billed boundary, not the biggest service. Query the CUR for internet egress, regional transfer, NAT Gateway bytes, Transit Gateway bytes, and load balancer processed bytes. Sort by account and resource, then use VPC Flow Logs to find the top talkers behind each charge. That gives you a short list of paths to change.
For each path, ask whether traffic can stay in one Availability Zone, go through a VPC endpoint instead of NAT, or be served from a cache. Fix the simple structural issues first. Moving S3 and DynamoDB traffic to gateway endpoints is quick. Keeping a chatty app and its cache in one zone is often quick too. Re-architecting a service to make fewer calls takes longer but can remove more traffic.
Watch the trade-offs. Interface endpoints charge per endpoint-hour and per GB, so do not place one in every subnet for every service without checking volume. Cross-zone load balancing can improve balance but adds transfer charges. Cross-region replication improves recovery time but copies data on every write. Keep the design that matches your recovery and latency needs, then remove the parts that do not.
- Pull a data transfer baseline from the Cost and Usage Report. Query the CUR for usage types tied to internet egress, cross-AZ traffic, NAT Gateway processing, and Transit Gateway processing. Group by account, region, and resource ID, then save the result as a monthly baseline.
- Tag shared network resources and assign owners. Put application, environment, and owner tags on NAT Gateways, Transit Gateway attachments, and load balancers. Create a shared services view for charges that serve several teams. Without an owner, nobody fixes the path.
- Move S3 and DynamoDB traffic to gateway endpoints. Add gateway endpoints to the route tables for each VPC that uses S3 or DynamoDB. Gateway endpoints do not add a data processing charge, and they keep that traffic off NAT Gateways. Check route table order and test from a private subnet.
- Use interface endpoints only where volume justifies them. For services such as SQS, SNS, Secrets Manager, and CloudWatch, compare NAT Gateway processing with the endpoint hourly and data charges. Place endpoints in the zones that need them, not every zone by habit. Confirm security groups and endpoint policies allow the calls.
- Keep chatty tiers in the same Availability Zone. Place an application instance and its cache or database read replica in the same zone when the recovery plan allows it. Use zonal load balancer targets and turn off cross-zone load balancing if it is not needed for balance. Keep the multi-AZ failover path, but do not send routine reads across zones.
- Cache and compress before traffic leaves the origin. Put CloudFront in front of static assets and cacheable API responses. Set cache headers, enable compression, and keep the origin in a nearby region. Watch the cache hit ratio, because a low ratio moves the cost rather than removing it.
- Trim replication and backup copies. Review S3 Cross-Region Replication, EBS snapshot copies, RDS cross-region read replicas, and backup vault copies. Keep the copies your recovery plan requires and delete stale rules. Check lifecycle policies so old objects do not keep replicating.
- Simplify VPC connectivity and shrink payloads. Use VPC peering for a small number of VPCs that need direct traffic. Use Transit Gateway when you need central routing and many attachments, and account for its data processing charge. Batch small API calls and compress request and response bodies so fewer bytes cross each boundary.
How to check it worked
Compare the same usage types in the CUR before and after each change. Look at bytes and charges separately, because a price change or a traffic shift can hide the result. Normalize by request count or active workload so growth does not make a good change look bad. Keep a log of the change date, resource, and expected effect.
Use CloudWatch to watch the paths you changed. NAT Gateway bytes out, Transit Gateway bytes, load balancer processed bytes, and CloudFront cache hit ratio show whether traffic moved as planned. VPC Flow Logs can confirm that S3 traffic now goes to the gateway endpoint. Check latency and error rates at the same time.
Set a budget alert for data transfer and review it monthly. Look for new cross-region replication rules, NAT Gateways in unused zones, and interface endpoints that no one owns. A saving that disappears after two billing cycles was probably a routing change, not a design fix.
Mistakes to avoid
Do not focus on internet egress alone. NAT Gateway processing and cross-AZ traffic can sit inside the account and never appear as egress. Do not assume same-region traffic is free, because cross-AZ paths are billed. Check the usage type before you call a path cheap.
Do not put every service behind an interface endpoint. Endpoint hours and data processing add up, especially across many zones. Do not disable cross-zone load balancing without checking target health and failover. Do not break multi-AZ recovery to save on transfer and call it optimization.
Do not copy every bucket and snapshot to a second region by default. Replication rules are easy to create and easy to forget. Do not route all VPC traffic through a Transit Gateway hub if a direct peering link is enough. Do not leave shared network costs untagged, or finance will see a saving that no team can explain.
If you want an outside read, a Cloud cost audit from Cloudverg is a two-week fixed-price review at $4,500 that includes a data transfer and egress review. Other teams run the same CUR queries internally or bring in a network engineer. The point is to rank each path by bytes and effort, then fix the top few.
Frequently asked questions
Why is AWS data transfer hard to track?
AWS splits transfer across internet egress, cross-AZ traffic, cross-region copies, NAT Gateway processing, and other line items. The Cost and Usage Report is the reliable place to see usage types and resource IDs. Cost Explorer is useful for a first look, but it can hide the resource behind a shared gateway.
Does traffic between AWS Availability Zones cost money?
Yes, cross-AZ traffic is billed even when both resources are in the same region. Keep chatty tiers in one zone where recovery needs allow it, and keep the multi-AZ failover path. Check load balancer cross-zone settings and database replica placement.
Do VPC endpoints always reduce NAT Gateway costs?
Gateway endpoints for S3 and DynamoDB keep that traffic off NAT Gateways without a data processing charge. Interface endpoints have hourly and data charges, so they pay off only when they replace enough NAT processing. Compare the endpoint cost with the NAT bytes for the same service and zones.