Skip to main content
emnode / learn
Cost

Reduce NAT Gateway data processing costs

A busy NAT Gateway's hourly fee is the small part — at scale the per-GB processing charge dwarfs it, and much of that traffic should never have touched NAT at all.

13 min·10 sections·AWS

Last reviewed

NAT data processing costs: the basics

Why a heavily-used NAT Gateway bill is mostly traffic, not uptime

A NAT Gateway is billed in two parts on completely different scales. The first is a flat $0.045 per hour just for being provisioned — about $32.40 per gateway per month — and it's the number most people anchor on. The second is $0.045 per GB of data processed in either direction, and on a busy gateway that's the part that quietly eats the bill. A NAT pushing 50 TB a month is roughly $2,250 in processing charges alone, on top of the trivial $32 hourly fee. The hourly charge is a rounding error; the data charge is the line item.

The check flags a gateway whose CloudWatch BytesOutToDestination and BytesInFromDestination metrics are high and sustained — not idle, but expensive. This is the opposite problem from an unused NAT. The gateway is doing real work; the question is whether it should be. A large share of that traffic is usually avoidable: requests to AWS services (S3, DynamoDB, ECR, CloudWatch, Secrets Manager) routed out through NAT when a VPC endpoint would carry them more cheaply or for free, chatty external APIs polled in a tight loop, and container image pulls dragging gigabytes through NAT on every deploy and autoscale event.

It's flagged because the asymmetry catches teams off guard. They sized the architecture around the $32 hourly fee, never modelled the per-GB charge, and only notice when the networking line on the bill quietly becomes one of the largest in the account. The fix is rarely "delete the NAT" — it's "stop routing the wrong traffic through it."

In this lesson you'll learn why a busy NAT Gateway's bill is dominated by the per-GB processing charge, how to identify the top talkers using VPC Flow Logs analysed through Athena or CloudWatch Logs Insights, and the fix ladder that drives the number down — free S3 and DynamoDB Gateway Endpoints first, Interface Endpoints for ECR and other AWS services where the per-GB endpoint cost beats NAT, then trimming genuinely public-internet egress. You'll see the Athena query that sums bytes by destination, the CLI to create a Gateway Endpoint, and the cost crossover math that tells you when an Interface Endpoint pays for itself versus when it doesn't.

Fun fact

The free endpoint that paid for an engineer

A data team ran a Spark job nightly that read 40 TB a month from S3, all of it from private subnets routed through a single NAT Gateway. The NAT's hourly fee was $32; its data-processing charge was $1,800 a month. Adding an S3 Gateway Endpoint — which AWS provides at no charge — dropped the S3 traffic off the NAT meter entirely. The change was three CLI commands and one route-table edit. The recurring saving was larger than the cloud-cost analyst's monthly salary, from a fix that took under an hour and changed nothing about how the job ran.

Tracing an expensive NAT in action

Marco is reviewing the networking spend for a fintech with 40-odd AWS accounts. The wastage tooling flags a NAT Gateway in the analytics-prod VPC, eu-west-1a, processing 38 TB last month — about $1,710 on the data meter, against a trivial $32 hourly fee. The number has climbed every month for a quarter, roughly tracking data-pipeline growth, so nobody questioned it.

He doesn't assume the traffic is waste, and he doesn't assume it's all legitimate either. The job is to split the gateway's traffic by destination: how much is going to AWS services that could use a private endpoint, and how much is genuine public-internet egress that has to pay the toll. VPC Flow Logs already feed into S3, so he queries them with Athena to sum bytes by destination address and pull the prefix-list ranges for AWS services.

The result is stark. Of 38 TB, 31 TB is destined for S3 and ECR — AWS-to-AWS traffic being routed out to the internet and back through the metered gateway. The remaining 7 TB is real third-party API and package-mirror traffic that stays on NAT. He adds a free S3 Gateway Endpoint and an ECR Interface Endpoint, re-points the route tables, and the NAT data charge falls by roughly 80% the following month.

VPC Flow Logs already land in S3. Query them with Athena to sum bytes by destination and surface the top talkers driving the NAT bill.

$ aws athena start-query-execution --query-string "SELECT dstaddr, SUM(bytes)/1e9 AS gb FROM vpc_flow_logs WHERE interface_id IN (SELECT eni FROM nat_enis) AND day >= '2026/05/01' GROUP BY dstaddr ORDER BY gb DESC LIMIT 10" --result-configuration OutputLocation=s3://my-athena-results/
dstaddr gb
-------------------------------
52.219.x.x (S3) 18420.5
3.5.x.x (ECR) 12930.1
99.84.x.x (API) 4110.8
151.101.x.x (PyPI) 2890.3
-------------------------------
# ~31 TB of 38 TB is S3 + ECR — AWS-to-AWS traffic paying NAT rates.

Bytes-by-destination from Flow Logs: the S3 and ECR rows are the recoverable spend.

Add an S3 Gateway Endpoint — it's free, attaches to the route tables, and immediately pulls S3 traffic off the NAT meter.

$ aws ec2 create-vpc-endpoint --vpc-id vpc-0analytics123 --vpc-endpoint-type Gateway --service-name com.amazonaws.eu-west-1.s3 --route-table-ids rtb-0deadbeef1234 rtb-0cafef00d5678
{
"VpcEndpoint": {
"VpcEndpointId": "vpce-0a1b2c3d4e5f6",
"VpcEndpointType": "Gateway",
"ServiceName": "com.amazonaws.eu-west-1.s3",
"State": "available",
"RouteTableIds": ["rtb-0deadbeef1234", "rtb-0cafef00d5678"]
}
}
# Gateway Endpoints are free — S3 traffic now bypasses NAT entirely.

A Gateway Endpoint for S3 costs nothing and instantly removes the biggest line from the NAT bill.

How NAT data processing billing actually worksdeep dive

A NAT Gateway is a managed Elastic Network Interface inside a single Availability Zone. The $0.045/hour provisioning charge starts the moment it transitions to available and is fixed regardless of load. The data-processing charge of $0.045/GB applies to every byte that traverses the gateway in either direction — outbound request and inbound response both count. On a busy gateway the processing charge dominates by one to two orders of magnitude: at 50 TB/month it's ~$2,250 of processing against ~$32 of uptime. There is no volume discount on the per-GB rate, so the bill scales linearly with traffic forever.

The cheapest fix is to stop AWS-bound traffic from ever reaching the gateway. S3 and DynamoDB have Gateway Endpoints, which AWS provides at no hourly and no per-GB charge — you attach them to route tables and the relevant traffic takes a private path off the NAT meter entirely. Everything else (ECR, CloudWatch, Secrets Manager, SQS, STS, and most other services) uses Interface Endpoints, billed at roughly $0.01/hour per endpoint per AZ (~$7.20/month each) plus $0.01/GB processed. The crossover versus NAT for a single Interface Endpoint is around 150 GB/month: above that the endpoint's $0.01/GB beats NAT's $0.045/GB and pays back its hourly fee. Below it, you can be paying $7.20/month for an endpoint that processes almost nothing — the same trap covered in the idle-VPC-endpoint lesson, so size endpoints to observed traffic, not to a wish list.

Two patterns inflate the data charge in ways teams miss. Container image pulls are the classic one: every deploy and every autoscale event drags the full image through NAT from a public registry or from ECR-over-internet, and a fleet scaling in and out can move terabytes a month in image layers alone — an ECR Interface Endpoint plus a pull-through cache fixes it. The second is cross-AZ chatter: traffic that crosses an AZ boundary on the way to or from the NAT picks up a separate $0.01/GB inter-AZ data-transfer charge on top of the NAT processing fee, so a NAT in the wrong AZ serving cross-AZ subnets is paying twice. VPC Flow Logs are the source of truth for both: enable them, query by destination, and the recoverable portion becomes obvious.

# Pull the NAT Gateway's monthly processed bytes to size the prize.
aws cloudwatch get-metric-statistics \
  --namespace AWS/NATGateway \
  --metric-name BytesOutToDestination \
  --dimensions Name=NatGatewayId,Value=nat-0abc123def456 \
  --start-time $(date -u -d '30 days ago' +%FT%TZ) \
  --end-time $(date -u +%FT%TZ) \
  --period 86400 --statistics Sum \
  --query 'sum(Datapoints[].Sum) / `1000000000`'  # bytes -> GB

# Confirm which AWS services already have endpoints in this VPC.
aws ec2 describe-vpc-endpoints \
  --filters Name=vpc-id,Values=vpc-0analytics123 \
  --query 'VpcEndpoints[].{Svc:ServiceName, Type:VpcEndpointType, State:State}'

What's the impact of high NAT data processing charges?

The direct cost scales linearly and without ceiling: $0.045/GB means 10 TB/month is $450, 50 TB is $2,250, 200 TB is $9,000 — per gateway. Unlike idle waste, there's no upper bound; it grows with every new customer, dataset, and deployment. For data-heavy and container-heavy workloads, the NAT processing line routinely becomes one of the top three networking costs in an account, and frequently the single largest line nobody can explain.

The recoverable share is usually large and the fix is cheap. S3 and DynamoDB Gateway Endpoints are free, so any byte going to those services through NAT is pure waste — there is no scenario where routing S3 traffic through NAT is correct once an endpoint exists. For ECR, CloudWatch, and the rest, the Interface Endpoint at $0.01/GB undercuts NAT's $0.045/GB by 78%, so above the ~150 GB/month crossover the endpoint both saves money and reduces latency by keeping AWS-to-AWS traffic off the public internet.

There's a sneaky second-order multiplier in container fleets. Image pulls don't show up as application traffic in anyone's mental model, but a service that scales from 5 to 50 tasks during peak, several times a day, pulling multi-gigabyte images each time, can move more data through NAT in image layers than the application does in real work. An ECR endpoint plus a pull-through cache often cuts the NAT bill more than the obvious application-traffic fixes do.

Finally, mis-placed NAT compounds with cross-AZ transfer. If subnets in AZ-b and AZ-c route through a NAT in AZ-a, every byte pays NAT processing and inter-AZ transfer. Consolidating NATs to save the $32 hourly fee can quietly increase the total bill if it forces cross-AZ traffic — the data charges swamp the uptime saving. The right lens is always total cost of the traffic path, not the count of gateways.

How do you bring NAT data processing costs down?

The goal isn't to delete the NAT — it's to take the avoidable traffic off its meter. Work the fix ladder in order: measure, move AWS traffic to endpoints, fix container pulls, then trim what's left.

1. Measure what's actually flowing with VPC Flow Logs

Enable VPC Flow Logs to S3 if they aren't already, then query by destination with Athena (or CloudWatch Logs Insights for smaller windows) to sum bytes per destination over 30 days. Map the top destinations to AWS service prefix lists. The output you want is one ratio: how much of the NAT data charge is AWS-to-AWS (recoverable) versus genuine public-internet egress (not). That single number sizes the prize and tells you whether endpoints are worth it.

2. Add free Gateway Endpoints for S3 and DynamoDB first

S3 and DynamoDB Gateway Endpoints have no hourly and no per-GB charge — they are an unconditional win the moment any S3 or DynamoDB traffic flows through NAT. Create the endpoint, attach it to the route tables serving the private subnets, and the traffic shifts to the private path immediately. This is almost always the single biggest reduction and there's no cost trade-off to weigh. Do it before anything else.

3. Add Interface Endpoints where per-GB beats NAT, sized to traffic

For ECR, CloudWatch, Secrets Manager, SQS, STS, and similar, Interface Endpoints process at $0.01/GB versus NAT's $0.045/GB, plus ~$7.20/month per endpoint per AZ. Above ~150 GB/month per service the endpoint wins; below it you're paying for an idle endpoint (see the idle-VPC-endpoint lesson). Use the Flow Logs data to add endpoints only for services that clear the crossover. For container fleets, an ECR endpoint plus a pull-through cache often delivers the largest single saving after the S3 Gateway Endpoint.

4. Trim or re-home the genuinely external traffic that remains

Whatever's left is real public-internet egress. Reduce it where you can: cache external API responses, pin and mirror package dependencies, and question chatty polling loops. For workloads that are almost entirely public-facing egress, consider whether they belong in a public subnet (no NAT needed) or behind a cheaper egress path. Confirm the NAT serves subnets in its own AZ so you're not stacking inter-AZ transfer on top of processing. The residual NAT bill should now track only traffic the business genuinely chose to send to the internet.

# 1. Add the free S3 Gateway Endpoint and attach it to the private route tables.
aws ec2 create-vpc-endpoint \
  --vpc-id vpc-0analytics123 \
  --vpc-endpoint-type Gateway \
  --service-name com.amazonaws.eu-west-1.s3 \
  --route-table-ids rtb-0deadbeef1234 rtb-0cafef00d5678

# 2. Add an ECR Interface Endpoint (two: api + dkr) for container image pulls.
for svc in ecr.api ecr.dkr; do
  aws ec2 create-vpc-endpoint \
    --vpc-id vpc-0analytics123 \
    --vpc-endpoint-type Interface \
    --service-name com.amazonaws.eu-west-1.$svc \
    --subnet-ids subnet-0aaa subnet-0bbb \
    --security-group-ids sg-0endpoint123 \
    --private-dns-enabled
done

# 3. Re-confirm the NAT data charge dropped on the next CloudWatch window.
aws cloudwatch get-metric-statistics --namespace AWS/NATGateway \
  --metric-name BytesOutToDestination \
  --dimensions Name=NatGatewayId,Value=nat-0abc123def456 \
  --start-time $(date -u -d '7 days ago' +%FT%TZ) \
  --end-time $(date -u +%FT%TZ) --period 86400 --statistics Sum

Quick quiz

Question 1 of 5

A NAT Gateway is processing 40 TB/month — about $1,800 in data charges. Flow Logs show 32 TB is S3 traffic and 6 TB is ECR image pulls, with the rest genuine external API calls. What's the highest-leverage first move?

You've completed Reduce NAT Gateway data processing costs. You now know why a busy NAT's bill is dominated by the $0.045/GB processing charge, how to split its traffic with VPC Flow Logs and Athena, and the fix ladder — free S3/DynamoDB Gateway Endpoints first, sized Interface Endpoints for ECR and friends, then trimming genuine external egress. The next time the networking line spikes, you'll reach for the bytes-by-destination query before you reach for any explanation about growth.

Back to the library