Since 1 February 2024 an IP address is a billable resource. The charge is small per address and merciless at scale, and the half of it people miss is that AWS charges the same rate for an address doing nothing.
Does AWS charge for IPv4?
Yes, for public IPv4. The Amazon VPC pricing page lists two rates and they are identical:
| Meter | Rate | What counts |
|---|---|---|
| In-use public IPv4 address | $0.005 per hour | Any public IPv4 on a resource launched in a VPC, plus Global Accelerator and Site-to-Site VPN tunnel endpoints |
| Idle public IPv4 address | $0.005 per hour | Any public IPv4 associated with your account but not used on a resource |
AWS states it plainly: "The price is the same whether the public IPv4 address is in-use public IPv4 addresses that is associated with an AWS resource you own, or an idle public IPv4 addresses in your AWS account not associated with any AWS resources." An Elastic IP you allocated in 2021 for a load balancer you deleted in 2022 is costing $3.65 a month, indefinitely, and shows up nowhere except a usage type.
Billing is finer-grained than hourly. The same page says "The bill is calculated in one-second increments, with a minimum of 60 seconds", so a short-lived instance is not charged a full hour the way a NAT Gateway hour is.
What is not charged?
Three exemptions, all documented, and they are narrower than people assume.
- Private IPv4 and IPv6. The VPC IP addressing documentation states "There is no charge for private IPv6 addresses." The charge is on public IPv4 specifically.
- Addresses you brought yourself. The AWS announcement that added public IPv4 to the free tier says "IPv4 addresses that you own and bring to AWS using Amazon BYOIP will continue to be free."
- Shared service addresses. Per the VPC pricing page, "Public IPv4 addresses that are not dedicated to your resource are not charged; for example, public IPv4 addresses associated with Amazon S3 that are not dedicated per S3 bucket."
The free tier is real but narrow. The same announcement gives 750 hours of public IPv4 per month for the first 12 months, and then adds the restriction that matters: "AWS Free Tier for Amazon EC2 applies to in-use public IPv4 address usage ... There is no change in pricing for idle public IPv4 addresses that you allocate in your account but don't attach to an EC2 instance." Idle addresses are billed from hour one, free tier or not.
Which resources are quietly creating charged addresses?
This is the part that turns a rounding error into a line item, because most charged addresses are not ones anybody allocated on purpose. AWS's guide to identifying and optimizing public IPv4 usage names the services that provision them for you: Elastic Load Balancers, NAT gateways, AWS Global Accelerator, and Site-to-Site VPN tunnel endpoints. EC2 instances in a subnet with auto-assign public IP enabled get one automatically too.
The VPC pricing page extends that list to "Amazon EKS, Amazon EMR, Amazon ECS, Amazon RDS, Amazon Workspaces". Two consequences worth thinking about before you go hunting for Elastic IPs:
- An internet-facing ALB across three Availability Zones holds an address per zone. Three addresses is $10.95 a month per load balancer, before it serves a request.
- A managed node group in a public subnet gives every node a public IPv4. A 50-node cluster is $182.50 a month in addresses alone. Moving those nodes to private subnets is the fix, and it interacts with your per-pod cost split not at all, because this charge lands under EC2 - Other rather than under EKS.
How do you find idle public IPv4 addresses?
Two usage types carry the whole charge. AWS names them as
PublicIPv4:InUseAddress and PublicIPv4:IdleAddress,
and notes they were added to the CUR before billing began "to help you estimate
public IPv4 related charges".
aws ce get-cost-and-usage \
--time-period Start=2026-07-01,End=2026-08-01 \
--granularity MONTHLY \
--metrics UnblendedCost UsageQuantity \
--group-by Type=DIMENSION,Key=USAGE_TYPE \
--filter '{"Dimensions":{"Key":"USAGE_TYPE",
"Values":["PublicIPv4:InUseAddress","PublicIPv4:IdleAddress"]}}'
Divide usage quantity by 730 to get the address count. If the idle number is anything but zero, you have allocated addresses attached to nothing, and that is free money:
aws ec2 describe-addresses \
--query 'Addresses[?AssociationId==`null`].[PublicIp,AllocationId,Domain]' \
--output table
For a per-resource inventory across accounts rather than a per-account total, AWS points at Public IP Insights, which it describes as "a new free feature of Amazon VPC IPAM that helps you monitor, analyze and audit public IPv4 address usage across your AWS accounts". The VPC pricing page confirms the pricing claim: "Public IP Insights is available for two or more Regions and accounts in your AWS Org even in the Free Tier of IPAM."
One caution from running this ourselves. describe-addresses only
sees Elastic IPs. Auto-assigned instance addresses are not Elastic IPs at all,
and the
EC2 instance IP addressing documentation
explains why: an auto-assigned address "is assigned to your instance from
Amazon's pool of public IPv4 addresses, and is not associated with your AWS
account". They are charged and they are invisible to the Elastic IP APIs, so
a clean describe-addresses result does not mean a clean bill.
Is a NAT Gateway cheaper than the addresses it replaces?
AWS publishes the arithmetic, which is unusual and worth using rather than reinventing. From the "Public IPv4 address optimization" section of the EC2 instance IP addressing page:
NAT gateway per hour + NAT gateway public IPs + NAT gateway transfer / Existing public IP cost. Existing public IP cost = $0.005 * 730 hours in a month * Number of public IPv4 addresses. If the total is less than 1, NAT gateways are cheaper than public IPv4 addresses.
Work it for the 50-node cluster above. Fifty addresses cost 0.005 x 730 x 50 = $182.50. One NAT Gateway costs about $32.85 a month in hourly charges, plus $3.65 for the address it holds, so the fixed side is roughly $36.50 and the ratio is well under 1 before any transfer. The variable is processing at $0.045 per GB, so the swap stops paying at roughly 3.2 TB a month through the gateway. That is the number to check against your own traffic, and it is exactly where a gateway VPC endpoint for S3 and DynamoDB changes the answer, because that traffic leaves the NAT meter entirely.
The other two documented moves from the same page are worth stating because they cost nothing: put instances behind "an elastic load balancer" and disable auto-assign, since "load balancers use a single public IPv4 address"; and where the only reason for a public address is administrative access, use "EC2 Instance Connect Endpoint instead", which connects "without requiring the instance to have a public IPv4 address".
Whichever way it goes, the charge lands in the EC2 - Other bucket in Cost Explorer rather than under a service of its own, which is the main reason it survives for years unexamined.