AWS VPC Design Best Practices: CIDR, Subnets, and Routing
Design an AWS VPC the right way: size the CIDR block, lay out public, private, and isolated subnets across availability zones, and wire route tables without common mistakes.

On this page
Creating a VPC takes a few clicks, and the default configuration AWS proposes will even connect it to the internet for you. That default is fine for a demo and a liability for anything real. The moment you add a database tier, a second availability zone, private endpoints, and a security review, the shortcuts become expensive to unwind.
A VPC design is mostly decided before the first subnet exists. The CIDR block sets how much room you have for growth and peering, the subnet layout sets your failure domains, and the route tables set what can reach what. Get those three decisions right and the rest of the network is easier to secure, document, and explain.
Start From the Availability Zone Model
An AWS region contains multiple availability zones, which are physically separate data centers with independent power and networking. Subnets are tied to exactly one zone, so if you place every resource in a single subnet, you have built a single zone system no matter how large the instance is.
Design the same set of subnet tiers in each zone you use. Two zones is the practical minimum, and three is common for services that need to survive a zone event with capacity to spare. The goal is not that every resource is duplicated. The goal is that losing one zone reduces capacity instead of removing a service entirely.
Keep the layout predictable. When the public, application, and data subnets have the same shape in every zone, an engineer can reason about a failure without opening a diagram. Mixed layouts are where “which subnet is that in” questions come from during an incident.
Size the VPC CIDR Before You Create Subnets
AWS accepts VPC IPv4 blocks between /16 and /28, and a /16 is the common starting point. A /16 contains 256 /24 subnets, which is enough for multiple tiers across several zones with room for services, load balancers, and future expansion. A /24 VPC feels generous until you start carving it into tiers and discover the data subnet cannot grow.
Choose the range from a planned private address space rather than from whatever the console suggests. The default VPC in many accounts uses 172.31.0.0/16, and reusing that block for a new VPC is a quick way to create a future routing conflict. RFC 1918 covers 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16, but the fact that every organization may reuse them does not make reuse safe inside your own connected estate.
Give each zone a predictable slice, such as a /20 per zone inside a /16, so that subnet addresses reveal where they live. If you plan to run Amazon EKS with a VPC CNI that assigns Pod addresses from the VPC, reserve a dedicated secondary CIDR rather than consuming the primary block. Containers can burn thousands of addresses that the original design never accounted for.
Lay Out Public, Private, and Isolated Subnets
Three tiers cover most architectures. A public subnet has a route to an internet gateway and is where internet facing load balancers and bastion hosts live. A private subnet has no inbound internet route but can reach the internet outbound through a NAT Gateway for patching and package installs. An isolated subnet has no internet route at all and reaches only what its endpoints and peering allow, which is where databases and internal services belong.
Remember that AWS reserves five addresses in every subnet: the first four and the last one. A /24 therefore yields 251 usable addresses rather than 256. That is rarely the constraint, but it matters when you size very small subnets for load balancers or interface endpoints in busy accounts.
Subnet sizing should follow the largest realistic number of elastic network interfaces, not the number of instances today. Auto scaling, load balancer nodes, and interface endpoints consume addresses in the subnets they attach to. A /24 per tier is a common and safe choice, and there is no reason to make production subnets smaller than a /26 unless you are deliberately conserving space.
Route Tables Decide Reachability
Every subnet is associated with exactly one route table, and that association is what actually makes it public or private. The VPC has a main route table that applies to subnets you have not explicitly associated, and it is worth replacing that default association for every real subnet so nothing inherits an unexpected default route.
Each route table always contains a local route for the VPC CIDR that cannot be removed, which is how subnets reach each other inside the VPC. On top of that, routes are matched using the longest prefix, so the most specific route wins. This is why adding a broad 0.0.0.0/0 route to a subnet silently turns it into a public one.
For private subnets, create a NAT Gateway in a public subnet in the same zone and point that zone’s private route table at it. A single NAT Gateway shared across zones saves a little money and creates both a cross zone traffic path and a single point of failure. In production, place one NAT Gateway per zone and route each zone’s private subnets to its local gateway.
Gateways and Endpoints
An internet gateway is a horizontally scaled, redundant component that you attach to the VPC once and reference from public route tables. It does not by itself make anything reachable. Reachability also depends on the instance having a public address, a security group that permits the traffic, and a network ACL that allows it.
A NAT Gateway provides outbound internet access for private subnets and is the usual reason private instances can still install packages. It is charged by the hour and per gigabyte processed, so it is worth routing traffic to AWS services through VPC endpoints instead. Gateway endpoints for Amazon S3 and DynamoDB are free, and interface endpoints powered by PrivateLink keep traffic on the AWS network while reducing NAT data processing charges.
For IPv6, use an egress only internet gateway for private outbound access rather than a NAT device, because IPv6 has no address translation. If you enable IPv6, treat its plumbing as a separate design with its own routes and security rules rather than assuming the IPv4 layout carries over.
Security Groups, Network ACLs, and Flow Logs
Security groups are stateful, allow only, and attach to elastic network interfaces, so return traffic is automatically permitted. Network ACLs are stateless, support both allow and deny, and apply at the subnet boundary in rule order, which means you must think about both directions of a flow. Use security groups as the primary control and keep NACLs broad unless you need a subnet level deny.
Reference other security groups by ID instead of copying CIDR blocks. A rule that allows the application security group to reach the database port survives renumbering, scaling, and subnet changes, while a hard coded /24 does not. Enable VPC Flow Logs to CloudWatch or S3 so that rejected traffic leaves a record. Without flow logs, a misapplied security group change looks identical to an application bug.
Plan for Growth and Future Connectivity
Do not consume the entire /16 on day one. Leave unused blocks so a new tier, a second cluster, or a service that needs its own subnet can be added without renumbering. When you add a second VPC, peering and AWS Transit Gateway both require non overlapping ranges, and a conflict that is invisible in one account becomes a blocked migration later.
The same discipline that applies to on premises address planning applies here: reserve a parent block per account, region, or environment, and record every allocation with an owner. If your organization already tracks IP space centrally, recording each VPC and subnet next to your on premises and other cloud ranges, for example through Obelinf’s IP address management, keeps the next peering request checkable against the whole estate instead of a single console.
Two toolkit pages are useful while you do this. The subnet calculator confirms how many usable addresses a proposed subnet actually offers after the AWS reservations, and the IP allocation planner helps you carve named blocks from a parent range before you create anything. A few minutes of planning prevents a renumbering project.
A Short VPC Design Review Checklist
Before you approve a VPC design, confirm that you can answer these questions:
- Which private parent block does this VPC come from, and what else uses that block?
- How many availability zones are in scope, and does each one have the same tier layout?
- Which subnets have a default route, and where does it point?
- Does each zone with private subnets have its own NAT Gateway, or is there a shared dependency?
- Are databases and internal services in subnets with no inbound internet route?
- Which AWS services are reached through VPC endpoints instead of the NAT Gateway?
- Do security groups reference other groups by ID rather than copied CIDR blocks?
- Is VPC Flow Logs enabled, and where are the logs retained?
- How much of the VPC CIDR is still unused, and where would a second cluster or tier fit?
The practical lesson is that a VPC is an address plan, a failure domain map, and a routing policy at the same time. Decide the CIDR from an organization wide plan, repeat a small set of subnet tiers across zones, attach route tables deliberately, and keep the record current. A VPC that is cheap to create is worth designing as if it will be expensive to change.
Frequently Asked Questions
What CIDR block should I use for an AWS VPC?
How many subnets should a VPC have?
Should databases go in a public or private subnet?
Do I need a NAT Gateway in every availability zone?
Free Tools
Put this into practice with the free calculators, reference tables, and checklists in the Obelinf toolkit.
Stop reaching for a spreadsheet
Obelinf keeps every subnet, device, circuit, and rack in one live source of truth, with audit logs and a topology view. Free for personal use.
Related Articles

Multi Cloud CIDR Planning: Avoid VPC and VNet Overlaps
Plan private CIDR space across AWS VPCs, Azure VNets, and Google Cloud VPCs without creating overlaps that break peering, VPNs, or future hybrid connectivity.
Read more
Terraform AWS VPC IPAM Tutorial
Create an AWS VPC IPAM pool with Terraform, provision address space, and allocate a VPC CIDR from the pool instead of hard coding each VPC range.
Read more
How to Use Terraform with IPAM for Network Subnets
Connect Terraform to IPAM with this hands on guide. Use Obelinf to find an approved subnet, read its CIDR safely, and plan an AWS network from it.
Read more