plainstackBook a free call
← All guides

Networking9 min read

Why is my NAT Gateway bill so high?

It's the line item people are most surprised by, because nothing in the console tells you it's happening.

By Plainstack/

NAT Gateway is the line item people are most surprised by, and there's a structural reason for that: in Cost Explorer it doesn't appear under its own name. It lands inside EC2 — Other, the same bucket that holds EBS volumes and snapshots and inter-AZ transfer. So the bill goes up, the biggest contributor is hidden inside a category nobody reads, and everyone assumes it's storage.

It usually isn't storage.

NAT Gateway charges you on two meters

This is the part that catches teams out. A NAT Gateway bills for:

  • Every hour it exists, per gateway, whether or not anything flows through it.
  • Every gigabyte it processes, on top of the normal data transfer charges that would have applied anyway.

At time of writing, in us-east-1, both meters run at roughly 4.5 cents — about $0.045 per hour and about $0.045 per gigabyte processed. Check the current figure for your region before you do any maths on it, because it varies and it changes.

The hourly meter alone is worth understanding. One gateway running continuously is roughly:

$0.045 × 730 hours ≈ $33 / month

That's per gateway. The standard high-availability pattern puts one in each Availability Zone, so a three-AZ VPC costs around $100 a month before a single byte moves. If you have a VPC per environment — production, staging, development — you're paying that three times over. Around $300 a month, for idle infrastructure, in an account where staging is empty most of the day.

Then the per-gigabyte meter runs on top. And this is where it gets expensive, because a lot of what flows through a NAT Gateway never needed to.

The four things that inflate the processing charge

1. Traffic to S3 and DynamoDB that should never touch NAT

This is the big one, and it's the first thing worth checking.

When a service in a private subnet talks to S3, the traffic goes out through the NAT Gateway by default. You pay the processing charge on every gigabyte — even though S3 is inside AWS and the traffic never really needed to leave the network.

Gateway endpoints for S3 and DynamoDB are free. There is no hourly charge and no per-gigabyte charge. You add them to your route table and the traffic stops going through NAT entirely.

DEFAULT PATH — BILLED TWICEYour servicePRIVATE SUBNETNAT GatewayS3SAME REGION$ / HOUR$ / GBPer gateway, per AZ — plus every gigabyte it processes.WITH A GATEWAY ENDPOINT — FREEYour servicePRIVATE SUBNETGateway endpointS3SAME REGIONNO HOURLY, NO PER-GB
The same request, two routes. The upper path is the default and is metered twice; the lower path costs nothing and is a route-table change.

If you back up to S3, ship logs to S3, or read datasets from S3 on any kind of schedule, this single change can remove a large fraction of your NAT processing charge, and it costs nothing to make. It's the closest thing to free money in AWS networking.

2. Cross-AZ routing that charges you twice

If a workload in AZ a routes to a NAT Gateway in AZ b, you pay the NAT processing charge and an inter-AZ data transfer charge on the same bytes. Both directions, in some cases.

This happens by accident more often than by design — usually a route table that wasn't updated when a subnet was added, or a single NAT that was deliberately shared to save on hourly costs and quietly moved the cost onto the transfer meter instead.

Check that each private subnet routes to a NAT Gateway in its own AZ.

3. Container image pulls

Every time a task starts and pulls an image from a public registry, those bytes go through NAT. A service that scales up and down frequently, or a CI pipeline that runs hundreds of jobs a day, can move a genuinely surprising volume this way — the same few hundred megabytes, over and over.

Options, roughly in order of effort:

  • Use ECR with a VPC interface endpoint, so pulls stay inside the network.
  • Use ECR's pull-through cache for upstream public images.
  • Make images smaller. This is good practice anyway and it directly reduces the meter.

4. Everything else that talks to the internet on a timer

Package installs during deploys, telemetry to third-party observability vendors, webhook traffic, external API polling, OS update checks. None of these are large individually. Together, on a chatty fleet running continuously, they add up.

How to find out what's actually happening

Two tools, in this order.

Cost Explorer, filtered by usage type. Filter to the NatGateway-Hours and NatGateway-Bytes usage types. The split between them tells you immediately which problem you have. Mostly hours means you're paying for idle gateways and the fix is architectural. Mostly bytes means something is moving a lot of traffic and the fix is to find out what.

VPC Flow Logs. If it's bytes, flow logs on the subnets behind the gateway will tell you which sources and destinations dominate. Enable them, let them run for a representative period, then query. Be aware that flow logs cost money to store, so set a retention policy when you enable them and turn them off again when you're done — otherwise you've swapped one silent cost for another.

The fixes, in the order worth doing them

  1. Add gateway endpoints for S3 and DynamoDB. Free, low risk, usually the biggest single reduction. Do this first, always.
  2. Verify per-AZ routing. Make sure no subnet routes to a gateway in a different AZ.
  3. Reconsider how many gateways non-production actually needs. Production availability requirements rarely apply to a staging environment that nobody uses at 3am. One gateway instead of three in non-prod cuts that environment's hourly charge by two thirds.
  4. Move image pulls inside the network with ECR and an interface endpoint.
  5. Evaluate interface endpoints for other high-volume services. These are not free — they carry their own hourly and per-gigabyte charges — so do the arithmetic. They're worth it above a certain volume and a waste below it.
  6. Ask whether the subnet needs outbound internet at all. Sometimes the honest answer is no, and the cheapest NAT Gateway is the one you delete.

When to leave it alone

Not every NAT Gateway charge is waste. If you're running production workloads that genuinely need outbound internet access across multiple AZs, the hourly cost is the price of an architecture you chose deliberately, and removing a gateway to save $33 a month while introducing a single point of failure in production is a bad trade.

The waste is in the accidental version: gateways in environments that don't need resilience, traffic that had a free path available, and routes that cross AZs for no reason. Fix those and leave the rest.

The short version

If you take one thing from this: check whether you have gateway endpoints for S3 and DynamoDB. It takes about five minutes to find out, the fix is free and low-risk, and in an account that moves real volume to S3 it can be the difference between a NAT bill you notice and one you don't.

Once that's done, the full checklist covers the rest of the account in the order worth working through it.

Check your own account

Does this apply to you? Find out in two seconds.

Drop a Cost Explorer export into the free teardown. It reads your service mix and tells you which of these patterns show up in your bill — in your browser, with no upload and no email.