NAT Gateway cost has two parts: a flat hourly charge for every gateway you run, and a per-GB charge on every byte that passes through it. In us-east-1 at the time of writing, both are $0.045 — about $32.85 a month per gateway just to exist, plus $45 for every terabyte processed. The hourly part is predictable. The per-GB part is the one that turns into a four-figure line item, and in most accounts I review, a large share of that traffic does not need to go through a NAT Gateway at all.
This guide covers how the charges work, how to find out exactly which traffic you are paying for, and the fixes in order: gateway endpoints, interface endpoints, IPv6, architecture changes and, where it makes sense, NAT instances.
How NAT Gateway pricing works
Every NAT Gateway bills three things, and people usually only know about the first:
| Charge | us-east-1 price | Notes |
|---|---|---|
| NAT Gateway hour | $0.045/hour | Per gateway, per AZ, whether or not traffic flows |
| Data processed | $0.045/GB | Every GB in either direction through the gateway |
| Data transfer | Standard EC2 rates | Internet egress ($0.09/GB after the free tier) and cross-AZ ($0.01/GB each way) are billed on top |
Two details catch people out. First, processing is charged on traffic in both directions, so downloading 500 GB of container images through the NAT costs about $22.50 in processing even though inbound internet data is free. Second, the recommended high-availability setup is one NAT Gateway per Availability Zone. Three AZs means roughly $98.55 a month in hourly charges before a single byte moves. If a private subnet in one AZ routes to a NAT Gateway in another, you also pay cross-AZ transfer on top of processing.
Each gateway also holds an Elastic IP, and every public IPv4 address is billed at $0.005 per hour. Small, but it is there.
Find which traffic you are paying for
You cannot fix what you cannot see. NAT charges hide inside the EC2-Other service in Cost Explorer, so start there.
Cost Explorer usage types
In Cost Explorer, filter Service to EC2-Other and group by Usage type. The NAT lines are named with a region prefix:
USE1-NatGateway-Hours— the hourly chargeUSE1-NatGateway-Bytes— data processed, in GB
If Bytes is much larger than Hours, you have a traffic problem, not a gateway-count problem. Switch the metric to Usage quantity to see the GB figure, and group by resource (with hourly or daily granularity and resource-level data enabled) to find which gateway is responsible.
VPC Flow Logs
Cost Explorer tells you how much; Flow Logs tell you where it is going. Enable Flow Logs on the NAT Gateway’s elastic network interface with a custom format that includes the packet-level addresses, because the standard srcaddr/dstaddr fields show the NAT’s own IP after translation:
aws ec2 create-flow-logs \
--resource-type NetworkInterface \
--resource-ids eni-0123456789abcdef0 \
--traffic-type ALL \
--log-destination-type s3 \
--log-destination arn:aws:s3:::my-flow-logs-bucket/nat/ \
--log-format '${interface-id} ${pkt-srcaddr} ${pkt-dstaddr} ${dstport} ${bytes} ${flow-direction}'Let it run for a day or two, then query it with Athena. A query summing bytes grouped by pkt-srcaddr and pkt-dstaddr will show you the top talkers. Look up the destination IPs against the published AWS IP ranges (ip-ranges.json): in my experience the top destinations are usually AWS services themselves — S3, ECR, CloudWatch, STS — which is exactly the traffic endpoints can take off the NAT.
Flow Logs cost money too (they are billed as vended logs), so turn them off or reduce the scope when the investigation is done.
Reduce NAT Gateway charges with gateway endpoints for S3 and DynamoDB
This is the first fix and usually the biggest. Gateway VPC endpoints exist for exactly two services, S3 and DynamoDB, and they are free: no hourly charge, no per-GB charge. Once the endpoint is attached to your private route tables, traffic to S3 in the same region goes straight to S3 and never touches the NAT.
aws ec2 create-vpc-endpoint \
--vpc-id vpc-0abc1234 \
--service-name com.amazonaws.us-east-1.s3 \
--vpc-endpoint-type Gateway \
--route-table-ids rtb-0private1 rtb-0private2 rtb-0private3No application change is needed; the route table sends S3 prefix-list traffic to the endpoint automatically. Two things to check: the endpoint only covers buckets in the same region as the VPC, and if you use an endpoint policy, make sure it allows the buckets your workloads need. ECR stores image layers in S3, so this one endpoint also removes most of the bytes from container image pulls.
Interface endpoints for everything else
For other AWS services — ECR API, CloudWatch Logs, STS, Secrets Manager, SSM, SQS — you need interface endpoints (PrivateLink). These are not free: at the time of writing they are about $0.01 per hour per AZ plus $0.01 per GB processed in us-east-1. So the math matters.
| Monthly traffic to one service | Through NAT (processing only) | Interface endpoint in 3 AZs |
|---|---|---|
| 50 GB | ~$2.25 | ~$21.90 + $0.50 |
| 1 TB | ~$46 | ~$21.90 + $10.24 |
| 5 TB | ~$230 | ~$21.90 + $51.20 |
The break-even for a three-AZ endpoint is roughly 600 GB a month to that service. Below that, the NAT is cheaper. The endpoints I most often find worth adding are ecr.dkr and ecr.api for container-heavy clusters, logs for chatty CloudWatch agents, and ssm/ssmmessages/ec2messages when you want Session Manager to work with no NAT at all. Remember to enable private DNS on the endpoint so SDKs pick it up without config changes.
IPv6 with an egress-only internet gateway
For outbound internet traffic to destinations that support IPv6, an egress-only internet gateway does the NAT job for IPv6 — outbound connections allowed, inbound blocked — with no hourly or processing charge. You still pay normal internet data transfer, but the $0.045/GB processing disappears.
The steps: add an IPv6 CIDR to the VPC and subnets, create the egress-only gateway, and add a ::/0 route to it from the private route tables. Many large destinations (the Ubuntu and Debian archives, Google and Cloudflare services) serve IPv6 today, but plenty of third-party APIs still do not, so this is a reduction rather than a replacement. If you want IPv6-only subnets to reach IPv4-only services, DNS64 plus NAT64 on the NAT Gateway handles that — but that traffic is back on the NAT meter.
Architecture fixes that remove NAT traffic
After endpoints, look at why the traffic exists at all:
- Keep NAT routing inside the AZ. Each private subnet should route to the NAT Gateway in its own AZ. A single shared NAT adds cross-AZ charges to every byte from the other zones.
- Cache container images. Nodes pulling the same image from Docker Hub on every scale-out event pay for it every time. Use ECR (with pull-through cache for public images) behind the S3 gateway endpoint.
- Stop shipping logs and metrics over the internet to third-party collectors at debug level. Filter at the agent.
- Put public workloads in public subnets where it is safe to do so. A web server behind an ALB with a tight security group does not need a NAT to reach the internet.
- Consolidate non-production. Dev and staging rarely need a NAT per AZ; one gateway with the risk accepted is a reasonable trade-off.
These are the kind of VPC decisions I make up front when doing an AWS server setup, because moving workloads between subnets later is more disruptive than getting the routing right on day one.
NAT instances: the cheap option and its trade-offs
A NAT instance is an EC2 instance doing the translation yourself. A small Graviton instance costs a few dollars a month and has no per-GB processing charge, which is why it is tempting for high-traffic, cost-sensitive setups. The open-source fck-nat project packages this as a ready-made AMI.
What you give up:
- Availability. A NAT Gateway is managed and redundant within its AZ. A NAT instance is a single instance you have to monitor and replace, usually with an Auto Scaling group of one and a script that updates the route table.
- Bandwidth. NAT Gateways scale to 100 Gbps. A small instance has burstable networking and will throttle under sustained load.
- Maintenance. OS patching, source/destination check disabled, iptables rules — all yours.
I use NAT instances for dev and staging and for production only when the traffic volume makes the per-GB saving significant and the team is comfortable owning it. For most production VPCs, endpoints plus IPv6 plus sensible routing get the bill down enough that the managed gateway is worth keeping.
When it is worth getting help
If NatGateway-Bytes is one of your top usage types and you cannot explain where the traffic goes, a day with Flow Logs and Athena usually answers it. If you would rather hand that off, NAT and data transfer review is a standard part of my AWS cost optimization service: I trace the traffic, add the endpoints that pay for themselves, and leave the ones that do not. It sits alongside the broader list in how to reduce your AWS bill. Small jobs are $20/hour, and larger pieces of work are a fixed price agreed in writing. You can get your NAT Gateway and transfer costs reviewed as a first step.
Frequently asked questions
Why is my NAT Gateway so expensive?
Usually because of the per-GB processing charge, not the hourly one. Container image pulls, S3 access, log shipping and software updates from private subnets all pass through the NAT unless you have VPC endpoints. Check the NatGateway-Bytes usage type in Cost Explorer to confirm.
Can I turn off a NAT Gateway at night to save money?
You can delete it and recreate it, but a new gateway gets a new ID and needs the route tables updated, and anything in private subnets loses outbound access while it is gone. It rarely saves enough to be worth the fragility outside of dev environments.
Do I need a NAT Gateway at all?
Only if instances in private subnets need to start connections to the internet or to AWS services without endpoints. If everything they talk to is reachable via VPC endpoints, or the workloads can live in public subnets safely, you may not need one.
Does traffic to S3 through a NAT Gateway incur data transfer charges?
Same-region traffic to S3 has no data transfer charge, but through a NAT Gateway you still pay the $0.045/GB processing fee. A gateway endpoint removes that fee entirely because the traffic no longer passes through the NAT.