Last reviewed: May 2026 · AWS, Azure and Google Cloud
Almost every painful cloud networking problem — failed peering, a VPN that will not come up, a Transit Gateway attachment that is rejected, a subnet that runs out of addresses eighteen months in — traces back to an address plan decided in the first hour of a project and never revisited.
This guide covers that planning process end to end: choosing the top-level block, dividing it across regions and environments, sizing subnets against real provider limits rather than textbook maths, and validating the plan before anything is deployed.
The single highest-leverage decision is to allocate every cloud network from one documented organisation-wide block. RFC 1918 gives you 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. In practice 10.0.0.0/8 is the only one large enough to carve a serious multi-account, multi-region estate from.
The failure mode when you skip this step is predictable, because both the AWS and Azure consoles suggest 10.0.0.0/16 by default. Teams accept the default independently, and eighteen months later three business-critical VPCs all claim the same range and none of them can ever be peered.
Use the free subnet finder to allocate from the supernet — paste what is already assigned and it returns the blocks that are genuinely free, correctly aligned.
| Provider | Allowed network CIDR | Practical default | Resizable later? |
|---|---|---|---|
| AWS VPC | /16 to /28 | /16 | Secondary CIDRs can be added; the primary cannot change |
| Azure VNet | /2 to /29 | /16 | Address spaces can be added or removed if unused |
| GCP VPC | Per-subnetwork, no network-level CIDR | /16 per region | Primary range can be expanded, never shrunk |
A /16 is the right default for anything production. It holds 256 /24 subnets, which is enough for multiple tiers across multiple availability zones with room left for growth. Drop to a /20 for genuinely small or single-purpose environments, but be aware you are trading away future headroom in exchange for address space you probably are not short of.
GCP is architecturally different and worth flagging: a GCP VPC is global, and subnetworks are regional within it. There is no network-level CIDR, so plan per-region ranges that do not collide across the whole VPC — including regions you have not deployed to yet.
This is the most common source of subnets that are quietly too small. The textbook figure of "total minus 2" is wrong in every cloud.
| Provider | Reserved | What they are | /24 usable | /28 usable |
|---|---|---|---|---|
| AWS | 5 | Network, VPC router, DNS, future use, broadcast | 251 | 11 |
| Azure | 5 | Network, gateway, two DNS, broadcast | 251 | 11 |
| GCP | 4 | Network, gateway, second-to-last, broadcast | 252 | 12 |
The overhead is fixed, so its impact grows as subnets shrink. On a /24 losing five addresses is noise. On a /28 it removes nearly a third of the block — which is exactly why teams that size a /28 for "14 hosts" hit a wall at eleven.
Managed services frequently demand a dedicated subnet with a minimum prefix. These are enforced at deployment time, so getting one wrong means a failed deployment rather than a warning.
| Service | Minimum | Notes |
|---|---|---|
| AzureFirewallSubnet | /26 | Name must match exactly |
| AzureBastionSubnet | /26 | Name must match exactly |
| GatewaySubnet (Azure VPN/ER) | /27 | /29 is the absolute floor but leaves no growth room |
| Application Gateway | /26 | Dedicated subnet, no other resources |
| AWS subnet (any) | /28 | Hard floor across the whole platform |
| AWS VPC (any) | /28 | Maximum size is /16 |
Because a /26 appears repeatedly on Azure, it is worth reading /26 vs /27 before finalising an Azure plan — the difference between those two prefixes is the difference between a working firewall deployment and a rejected one.
Work top down, and divide on boundaries that mean something operationally:
Split the VPC block evenly across the AZs you will use. Keeping AZ boundaries aligned makes route tables, NACLs and failover reasoning far simpler than interleaving them.
Within each AZ, divide into public, private and data tiers. Uniform sizing per tier keeps security group and firewall rules readable — you can express "all private subnets" as a short list of prefixes rather than a long one.
Neither AWS nor Azure lets you resize a subnet after creation. Growing one means building a new subnet and migrating every resource in it, so size for the host count you expect in two years, not today's.
Reserve free blocks between tiers. Address space is effectively free; an emergency re-plan because there is nowhere to put a new tier is not.
Where tiers have genuinely different host counts, variable-length subnetting avoids waste — the VLSM calculator allocates each tier the smallest block that fits and exports the result as Terraform, AWS CLI, Azure CLI or gcloud commands.
For choosing between adjacent sizes: /24 vs /25, /26 vs /27, /28 vs /29, and /30 vs /31 for point-to-point links.
Peering and transit rely on unambiguous routing. If the same prefix exists on both sides, the router cannot decide where traffic belongs — so all three providers reject the connection outright.
This affects VPC peering, VNet peering, Transit Gateway attachments, Azure Virtual WAN hubs, site-to-site VPNs and Direct Connect / ExpressRoute circuits. It is also the hardest class of mistake to recover from: the fix is re-ranging one side, which on AWS and Azure means rebuilding its subnets and migrating everything in them.
Checking a plan takes minutes. Recovering from a bad one takes weeks.
The bulk calculator reads terraform show -json, aws ec2 describe-subnets output and console CSV exports directly, so you can validate the plan you are actually about to apply rather than a transcription of it:
terraform show -json | pbcopy # paste straight into the bulk calculator aws ec2 describe-subnets \ --filters "Name=vpc-id,Values=vpc-xxxxxxxx" \ --output json
Each provider words the same underlying problem differently. These pages cover the exact message, the cause, and the fix:
A /16 is the practical default for a production VPC because it holds 256 /24 subnets and leaves room to grow. Use a /20 for small or single-purpose environments. AWS accepts VPC CIDRs between /16 and /28. The block must not overlap any other network you will ever peer with, so allocate it from a documented organisation-wide supernet rather than accepting the console default.
AWS reserves 5 addresses per subnet, Azure reserves 5, and GCP reserves 4. On AWS these are the network address, the VPC router, the DNS server, one reserved for future use, and the broadcast address. This means a /28 gives 11 usable addresses on AWS rather than the textbook 14, and the effect is proportionally larger the smaller the subnet.
Peering builds routes between the two networks, and overlapping ranges make those routes ambiguous — the router cannot determine which side a given destination belongs to. AWS, Azure and GCP all reject peering between networks with overlapping address space, and the only fix is to re-range one side, which usually means rebuilding its subnets.
Not on AWS or Azure — a subnet's CIDR is fixed at creation, so growing it means creating a new subnet and migrating resources. GCP allows a subnetwork's primary range to be expanded but never shrunk. Because of this, size subnets for expected growth from the start rather than planning to adjust later.