# Idle NAT Gateway

> A NAT Gateway costs roughly $32 a month before a single byte crosses it. ZopNight checks four byte-counter metrics plus ActiveConnectionCount over 30 days, and reports the full cost as recoverable when all of them are flat. An unused gateway has no partial value.

Source: https://zop.dev/integrations/aws/recommendations/idle-nat-gateway
Updated: 2026-08-19

---

## The hourly charge is the point

NAT Gateway pricing has two parts: [about $0.045 per hour just to exist, plus a per-GB data
processing charge](https://aws.amazon.com/vpc/pricing/) on top. The hourly part is roughly $32 a month and accrues whether or not
anything routes through it. That is what makes an unused gateway worth finding: a fixed
cost with zero utilisation, not a variable one that scales down on its own.

## Why five metrics

Traffic can flow in four directions and the rule checks all of them, using [the byte counters a NAT Gateway publishes to CloudWatch](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway-cloudwatch.html): `BytesInFromSource`,
`BytesOutToDestination`, `BytesInFromDestination` and `BytesOutToSource`. A gateway serving a
one-way workload would look idle on two of those and busy on the others.

`ActiveConnectionCount` is the fifth axis, and it catches a gateway holding open connections
that are transferring almost nothing. Such a gateway is present, but not moving bytes.

All five flat across 30 days is the bar.

## Where these come from

Almost always a multi-AZ VPC built from a template. The pattern puts one NAT Gateway per
availability zone for resilience, which is correct for production and expensive in a
development VPC where nothing routes through two of the three.

The other common source is a private subnet that was given a NAT route for an outbound
dependency that later moved to a VPC endpoint. The endpoint is cheaper and the gateway stays.

## Reading BytesOutToDestination for the gateway

```bash
aws cloudwatch get-metric-statistics \
  --namespace AWS/NATGateway --metric-name BytesOutToDestination \
  --dimensions Name=NatGatewayId,Value=nat-0123456789abcdef0 \
  --start-time "$(date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)" \
  --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --period 86400 --statistics Sum
```

## Before deleting

Check the route tables that point at it. Deleting a NAT Gateway with a live route leaves a
blackhole route behind, and instances in that subnet lose outbound access with no obvious cause.
Remove the route first, confirm nothing breaks, then delete the gateway and release its Elastic
IP, which otherwise keeps billing on its own.
