Planning VPC address space you will not regret
Subnetting is easy arithmetic and hard planning. How to size a VPC, why AWS takes five addresses per subnet, and the allocation habits that keep the next environment from needing a migration.
· 8 min read
The arithmetic of subnetting takes a minute to learn and a calculator to do quickly. The planning is the hard part, because address space is the one decision in a VPC that is genuinely expensive to change later: you cannot resize a subnet, only replace it, and replacing it means recreating everything in it.
Start much larger than you need
Take a /16 for the VPC unless you have a reason not to. That is
65,536 addresses, which sounds absurd for a service with six instances — and
costs nothing. Private address space is free; a re-addressing project is not.
Then divide it with room to spare. A common shape for a three-availability-zone region:
10.20.0.0/16 the VPC
10.20.0.0/20 public subnets (three /22s, one per AZ)
10.20.16.0/20 private subnets (three /22s, one per AZ)
10.20.32.0/20 data subnets (three /22s, one per AZ)
10.20.48.0/16 … unallocated — deliberately
Roughly half the range stays unallocated. That is not waste, it is the space the next tier, the next AZ or the next environment will need.
Why AWS gives you five fewer addresses
Every subnet loses its first address (the network address) and its last (the broadcast address) — that is IP, not AWS. AWS then reserves three more: the VPC router, the Amazon DNS resolver, and one kept for future use. So:
- a
/24has 256 addresses, 254 usable normally, 251 on AWS; - a
/28— the smallest subnet AWS allows — has 16, and just 11 usable.
This bites hardest with Fargate tasks or EKS pods using the VPC CNI, where
every task or pod takes a real subnet address. A /28 that looks
adequate for eleven tasks has no room for a rolling deployment, which needs
headroom for the new tasks while the old ones drain. The
subnet calculator has an AWS mode that
accounts for the five.
Leave room between allocations
Allocate on boundaries you can extend into. If your first private subnet is
10.20.16.0/22, the next contiguous /22 is free for a
fourth AZ. If instead you pack subnets adjacently by exact current need, the
next change has to go somewhere unrelated and your address plan stops being
readable — which is how you end up with a spreadsheet nobody trusts.
Never overlap, even with things you do not peer to yet
Two VPCs with overlapping CIDRs cannot be peered, cannot both be reached over the same Transit Gateway, and cannot both be routed to from an on-premises network. The overlap is usually discovered years later, by which point one side has to be re-addressed.
The habit that prevents it: keep one register of every allocated block — including the ranges your offices, VPN clients and Kubernetes services use — and check a new block against it before creating anything. The CIDR calculator's overlap checker takes a list and reports every conflicting pair.
Two ranges deserve particular care. Docker's default bridge is
172.17.0.0/16, which collides with an RFC 1918 allocation people
reach for often. And 100.64.0.0/10 — carrier-grade NAT space — is a
useful pressure valve for EKS secondary CIDRs precisely because it is not
RFC 1918, so it rarely clashes with anything on-premises.
A checklist before you apply
- Does the new block overlap anything in the register, including VPN and Kubernetes service ranges?
- Do the subnets have room for a rolling deployment at peak, with AWS's five reserved addresses subtracted?
- Is there contiguous free space next to each tier for another AZ?
- Is the VPC big enough that the next environment fits the same pattern?