There is a VPC endpoint that AWS does not charge for at all, and it covers the two services most likely to be driving your NAT Gateway bill. There is also one that bills by the hour and by the gigabyte, and which people reach for first because it is the one that appears everywhere in the console. Knowing which is which is worth real money.
Which endpoint types matter for cost?
AWS documents five endpoint types in all: Interface,
Gateway, GatewayLoadBalancer, Resource
and ServiceNetwork are the values
DescribeVpcEndpoints
returns. Two of them decide whether your S3 and DynamoDB traffic is free or
metered, and those are the two below.
Per the gateway endpoints documentation: "gateway VPC endpoints provide reliable connectivity to Amazon S3 and DynamoDB without requiring an internet gateway or a NAT device for your VPC. Gateway endpoints do not use AWS PrivateLink, unlike other types of VPC endpoints."
Then the sentence that matters:
"There is no additional charge for using gateway endpoints."
Interface endpoints are the PrivateLink kind, and they are billed. AWS's own comparison in the AWS PrivateLink for Amazon S3 documentation puts it in a single row: gateway endpoints are "Not billed", interface endpoints are "Billed".
| Gateway endpoint | Interface endpoint | |
|---|---|---|
| Billed | No | Yes |
| Services | Amazon S3 and DynamoDB only | AWS services that integrate with AWS PrivateLink |
| Addressing | "Use Amazon S3 public IP addresses" | "Use private IP addresses from your VPC" |
| DNS | "Use the same Amazon S3 DNS names" | "Require endpoint-specific Amazon S3 DNS names" |
| From on premises | "Do not allow access from on premises" | "Allow access from on premises" |
| From another Region | "Do not allow access from another AWS Region" | Allowed via VPC peering or Transit Gateway |
| Mechanism | A route table entry to a prefix list | One or more ENIs in your subnets |
Both keep traffic on the AWS network. AWS states it flatly for the pair: "in both cases, your network traffic remains on the AWS network."
What does an interface endpoint cost?
Two meters, the same shape as a NAT Gateway: something per hour and something per gigabyte.
The Access AWS services through AWS PrivateLink documentation states both meters in one line: "you are billed for each hour that your interface VPC endpoint is provisioned in each Availability Zone. You are also billed per GB of data processed."
Note each Availability Zone, and note that this is not an edge case: AWS's own resilience guidance pushes you straight into the multiplier. "Configure at least two Availability Zones per VPC endpoint", because with a single zone, "if Availability Zone 1 is impaired, the resources in Availability Zone 2 lose access". The mechanism is one endpoint network interface per subnet, and you pay by the hour for each. An endpoint across three zones is three hourly charges, so an estimate built from a single hourly figure is a third of the real number.
Read the current hourly rate on the AWS PrivateLink pricing page rather than from here. It varies by Region and changes, and a stale rate in a blog post is worse than no rate.
Data processing is tiered, and as published on that pricing page the tiers are enormous:
| Data processed per month | Rate per GB |
|---|---|
| First 1 PB | $0.01 |
| Next 4 PB | $0.006 |
| Anything over 5 PB | $0.004 |
The practical reading: unless you are moving a petabyte a month, you are on the first tier and the effective rate is a flat cent per GB. Do not model savings from tier progression that you will never reach.
Why does a gateway endpoint save money at all?
Because of what it replaces, not what it costs. AWS's description of life without one: "instances in a private subnet can't send traffic to Amazon S3 or DynamoDB, because by definition private subnets do not have routes to an internet gateway. To enable instances in the private subnet to send traffic to Amazon S3 or DynamoDB, you would add a NAT device to the public subnet and route traffic in the private subnet to the NAT device."
So without a gateway endpoint, every byte an application in a private subnet reads from or writes to S3 is a byte through your NAT Gateway, picking up the per-GB processing charge on the way. With one, that traffic takes a route table entry that costs nothing. For a workload doing bulk S3 reads out of a private subnet, this is usually the single largest network cost line in the account, and the fix is free and takes minutes.
AWS makes the cost argument itself in the S3 documentation, which is rare enough to be worth quoting: "this approach allows you to optimize your networking costs by using gateway endpoints, which are not billed, for your in-VPC traffic."
One nuance to keep you honest about the mechanism. Traffic to S3 through an internet gateway is not "leaving AWS" in the way internet egress does: "while traffic to Amazon S3 or DynamoDB traverses the internet gateway, it does not leave the AWS network." The charge you avoid with a gateway endpoint is primarily the NAT Gateway processing charge, not internet data transfer. Getting that distinction right matters when you are forecasting the saving.
What will a gateway endpoint silently not cover?
Three documented gaps, each of which looks like a broken endpoint:
- Other Regions. "Traffic that's destined for the service (Amazon S3 or DynamoDB) in a different Region goes to the internet gateway because prefix lists are specific to a Region." A cross-Region bucket read bypasses your endpoint entirely and goes back to paying.
- Subnets you did not associate. "All instances in the subnets associated with a route table associated with a gateway endpoint automatically use the gateway endpoint… Instances in subnets that aren't associated with these route tables use the public service endpoint, not the gateway endpoint." Add a subnet later, forget the route table, and that subnet quietly pays.
- A more specific route. "If there is a route that specifies the exact IP address range for the service in the same Region, that route takes precedence over the endpoint route." Longest prefix match wins, and a hand-written CIDR route beats your endpoint.
None of these produce an error. They produce a bill. That is the recurring theme in AWS network cost: the failure mode is silent and expensive rather than loud and free.
Should you run both types together?
Often, yes, and AWS documents the pattern explicitly: "you can create interface endpoints and retain the existing gateway endpoint in the same VPC… By taking this approach, you allow in-VPC applications to continue accessing Amazon S3 through the gateway endpoint, which is not billed. Then, only your on-premises applications would use interface endpoints."
There is even a setting for it. When you enable private DNS on an S3 interface endpoint, "the Enable private DNS only for inbound endpoints option is selected by default. If this option is selected, your applications use only interface endpoints for your on-premises traffic. This in-VPC traffic automatically uses the lower-cost gateway endpoints."
That default is doing real financial work, and it has a prerequisite: "to take advantage of the lowest cost network path when using Enable private DNS only for inbound endpoints, a gateway endpoint must be present in your VPC." AWS will refuse the setting without one, with the error "to set PrivateDnsOnlyForInboundResolverEndpoint to true, the VPC must have a gateway endpoint for the service." If someone clears that checkbox to "simplify DNS", all in-VPC S3 traffic starts flowing through the billed endpoint instead of the free one.
How do you check what you have?
List the endpoints and their types:
aws ec2 describe-vpc-endpoints \
--query 'VpcEndpoints[].[VpcEndpointId,VpcEndpointType,ServiceName,VpcId]' \
--output table
Gateway and Interface are both valid values of the
vpc-endpoint-type filter, so you can narrow directly. A VPC with
heavy S3 traffic from private subnets and no Gateway-type
endpoint for S3 is the finding worth acting on. Then confirm the route
actually reaches your subnets, since an endpoint that exists but is associated
with the wrong route tables is the common half-configured state.
RouteTableIds is documented as "(Gateway endpoint) the IDs of the
route tables associated with the endpoint", so it is populated only for the
type that matters here:
aws ec2 describe-vpc-endpoints \
--filters Name=vpc-endpoint-type,Values=Gateway \
--query 'VpcEndpoints[].[VpcEndpointId,ServiceName,RouteTableIds]' \
--output table
To see whether the traffic is actually taking the endpoint, the
interface-type field in
VPC Flow Logs includes
vpc_endpoint as a value, alongside nat_gateway.
Comparing volume across those two is the direct measurement of whether your
endpoint is doing its job.
What does this not fix?
- Anything other than S3 and DynamoDB. Gateway endpoints support exactly those two services. Everything else is an interface endpoint with an hourly charge per AZ, and for a low-traffic service that can cost more than the NAT processing it replaces. Interface endpoints are worth it for volume or for a private-connectivity requirement, not automatically.
- Cross-AZ traffic. An endpoint changes the path to the service, not which zone your workload sits in.
- The NAT Gateway itself. Removing S3 traffic from it cuts processing charges, but the hourly charge continues for as long as the gateway exists, and anything else in the subnet still needs it.
- Attribution. Endpoint charges appear under their own usage types, and splitting them by team needs the same machinery as any other shared resource, covered in why cost allocation tags show up empty.
If you take one action from this: check every VPC for an S3 gateway endpoint. It is free, AWS says so in one sentence, and it is the least ambiguous saving in AWS networking.