Skip to content

Reduce AWS NAT Gateway cost

NAT Gateway is the most-billed networking service on AWS, and the one with the most predictable fix. This guide walks through the two pricing levers, the four common sources of "wait, where is all this traffic coming from?", and the Terraform PR that typically pays for itself in a month.

Run the NAT Gateway calculator →


How NAT Gateway pricing works

There are two charges, both flat (no per-second granularity beyond the hourly):

Charge Rate (us-east-1) What it means
Hourly uptime $0.045/hour Every NAT Gateway is billed $0.045 for every hour it exists, idle or saturated. ~$33/mo per NAT GW.
Data processing $0.045/GB Every byte that flows through the NAT GW is billed at $0.045/GB. This is on top of any inter-AZ or egress charges.

The data-processing charge applies regardless of where the traffic is going — S3, DynamoDB, an EC2 instance in the same region, an external API. AWS doesn't discount "traffic to my own AWS services". You can sidestep it for some destinations (see "Endpoints" below).

Region note

Rates above are for us-east-1. Most other regions are within ±10%. ap-south-2 and the China regions are exceptions.


The four sources of "where is all this traffic coming from?"

1. S3 + DynamoDB traffic

The single biggest contributor in most clusters. Every pod that pulls a manifest from S3, every Lambda that reads a config blob, every job that writes to DynamoDB — all paying $0.045/GB through the NAT GW.

Fix: add a Gateway endpoint for S3 and DynamoDB. They are free (no hourly, no per-GB). One-line Terraform per VPC.

resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.${var.region}.s3"
  route_table_ids   = aws_route_table.private[*].id
  vpc_endpoint_type = "Gateway"
}

After applying: traffic from private subnets to S3 stops touching the NAT GW immediately. No app changes needed; routing tables take care of it.

2. ECR image pulls

Every container start pulls layers from ECR — which lives behind a public AWS endpoint. Each EKS node-replacement, each Karpenter scale-up, each kubectl rollout restart re-pulls those layers through the NAT GW. For a busy cluster this can be tens of GB/day.

Fix: add interface endpoints for ecr.api and ecr.dkr. They cost $0.01/hour each ($7.30/month per endpoint) but stop the per-GB ECR traffic. Anything more than ~160 GB/month of ECR traffic and the endpoints pay for themselves.

3. CloudWatch Logs

EKS nodes ship logs to CloudWatch Logs by default. Every byte of log data is a byte through the NAT GW.

Fix: add an interface endpoint for logs. Same math as ECR — break-even at low GB/month.

4. Cross-account traffic

You'd think traffic from one VPC to another VPC in your own org is "internal" — it isn't. If it leaves the VPC via the NAT GW (rather than over a Transit Gateway or VPC peering), you pay both the NAT toll and the inter-region transfer.

Fix: Transit Gateway or VPC peering, not NAT, for VPC-to-VPC traffic. Transit Gateway has its own per-GB charge, but it's typically cheaper than NAT for large flows and unlocks the routing flexibility you'll want anyway.


VPC endpoints — the cheat sheet

Service Endpoint type Cost Break-even
S3 Gateway Free Immediate
DynamoDB Gateway Free Immediate
ECR (api + dkr) Interface $0.01/hr each ~160 GB/mo
CloudWatch Logs Interface $0.01/hr ~160 GB/mo
Secrets Manager Interface $0.01/hr ~160 GB/mo
KMS Interface $0.01/hr ~160 GB/mo
STS Interface $0.01/hr ~160 GB/mo

Each endpoint is a few lines of Terraform. The S3/DynamoDB pair is the obvious starting point — they're free and they're typically the biggest dollar cut.


Worked example

A typical Series-A SaaS company:

  • 3 NAT gateways — two AZs in prod + one in staging.
  • 4,000 GB/month processed (visible in Cost Explorer under usage type NatGateway-Bytes).
3 × $0.045/hr × 730 hr  = $98.55/mo  (hourly)
4,000 GB × $0.045       = $180.00/mo (data processing)
                          ────────
Total                     ~$279/mo (~$3,348/yr)

After adding the S3 + DynamoDB Gateway endpoints (free), ~60% of the data-processing slice typically drops off the NAT bill: $108/month back in your AWS budget for one Terraform PR. Adding ECR + CloudWatch Logs interface endpoints takes another 20–30% off the remaining slice once the break-even threshold is cleared.


When to not use endpoints

Endpoints are almost always a win, but two cases need care:

  1. Cross-region access. Endpoints are regional. If you need access to S3 buckets in another region, the endpoint won't catch that traffic — keep the NAT path.
  2. Public-internet APIs. Endpoints only exist for AWS services. Traffic to api.openai.com / api.stripe.com / your own external APIs still pays NAT toll.

How to migrate without breaking anything

The migration is a no-downtime change because routing-table updates are atomic. But two things to watch:

  1. Audit your IAM policies. Some aws:SourceVpc / aws:SourceVpce conditions only fire when traffic flows through an endpoint. Make sure your S3 bucket policies don't Deny traffic that doesn't come from a known endpoint — that breaks the moment you add one.
  2. Test in staging first. Routing-table changes are atomic but DNS resolution for some endpoints is enabled separately (private_dns_enabled). Get the staging rollout right before doing prod.

Where to go next

Want us to find your endpoint opportunity?

Book a free 30-minute audit and we'll go through your VPC Flow Logs + NAT-GW data-processing metrics, then come back with the exact list of endpoints to add, ranked by $/month saved.

Book a free audit →