The problem
NAT Gateways keep charging by the hour even when they are not moving any meaningful traffic. The waste is easy to miss because the gateway often survives environment shrinkage, partial teardown, or copied VPC patterns long after the original outbound requirement disappeared.
Why it happens
- Private subnet designs get copied into dev or staging environments that barely make outbound requests.
- Route-table cleanup lags after workload teardown or environment consolidation.
- Teams optimize compute and storage first while fixed networking charges keep running in the background.
What this means for cost
Estimated monthly
$32 to $65/mo
Estimated annual
$384 to $780/yr
This waste pattern often shows up as $32 to $65/mo in recurring monthly cost, or roughly $384 to $780/yr if it sits untouched for a year.
How to detect idle NAT gateway cost
The clearest pattern is a public NAT Gateway that stays up long enough to incur its hourly charge while CloudWatch shows no recent byte or connection activity at all.
Start with NAT Gateway inventory:
aws ec2 describe-nat-gateways \
--query 'NatGateways[].{NatGatewayId:NatGatewayId,State:State,ConnectivityType:ConnectivityType,VpcId:VpcId,SubnetId:SubnetId,CreateTime:CreateTime}'
Then inspect the recent CloudWatch metrics for bytes and connection attempts:
aws cloudwatch get-metric-statistics \
--namespace AWS/NATGateway \
--metric-name BytesOutToDestination \
--dimensions Name=NatGatewayId,Value=nat-0123456789abcdef0 \
--start-time 2026-04-10T13:30:00Z \
--end-time 2026-04-10T14:00:00Z \
--period 300 \
--statistics Sum
aws cloudwatch get-metric-statistics \
--namespace AWS/NATGateway \
--metric-name ConnectionAttemptCount \
--dimensions Name=NatGatewayId,Value=nat-0123456789abcdef0 \
--start-time 2026-04-10T13:30:00Z \
--end-time 2026-04-10T14:00:00Z \
--period 300 \
--statistics Sum
Cloud Waste Hunter keeps the first-pass boundary intentionally narrow:
- public NAT Gateway only
availablestate only- at least 30 minutes old
- zero
BytesInFromSource - zero
BytesOutToDestination - zero
ConnectionAttemptCount
That means this page is about explicit inactivity on the NAT Gateway resource itself, not a fuzzy “low traffic” heuristic.
How to fix idle NAT gateway cost
Treat this as a review-first networking cleanup item, not an automatic delete:
Before deletion, confirm:
- Which private subnets and route tables still point at the gateway.
- Whether outbound package updates, license calls, or control-plane traffic still need internet egress.
- Whether VPC endpoints, a smaller environment footprint, or another egress path should replace the NAT Gateway first.
When the gateway is truly unnecessary, update the downstream route tables and then remove it:
aws ec2 delete-nat-gateway --nat-gateway-id nat-0123456789abcdef0
Caveats and overlap boundaries
Even zero recent activity does not prove a NAT Gateway is disposable. Some environments keep a quiet gateway for rare deployment jobs, emergency package downloads, or failover paths that matter more than their day-to-day traffic volume.
That is why Unused Elastic IPs stays separate. That detector is about detached public IP allocations. This page is about an actual NAT Gateway resource whose recent CloudWatch activity has gone fully quiet.
How Cloud Waste Hunter helps
Cloud Waste Hunter can surface idle NAT Gateways with explicit byte and connection-attempt evidence, age gating, resource metadata, and fixed hourly savings estimates so teams can fold egress cleanup into broader AWS environment rationalization. For adjacent infrastructure cleanup, review the AWS Idle and Underused Resources guide.
FAQ
Is low traffic enough to delete a NAT Gateway?
No. In fact, v1 does not fire on merely low traffic. It only opens a finding when the gateway is old enough and CloudWatch shows no recent bytes or connection attempts at all.
What exactly causes this detector to fire?
The detector requires a public NAT Gateway in `available` state, at least 30 minutes of age, and zero `BytesInFromSource`, zero `BytesOutToDestination`, and zero `ConnectionAttemptCount` over the same 30-minute lookback.