GCP Subnets Explained: CIDR, Regional Design, Secondary Ranges, and AWS Differences

A subnet is the IP address range your VMs live in. In GCP, subnets are regional: one subnet automatically covers every zone in a region, which is the opposite of how AWS works. Understanding this difference, planning CIDR ranges carefully, and enabling the right subnet-level settings before you start building will save you from painful re-addressing work later.

Simple explanation

Analogy

Think of your VPC as a private office building. The building spans multiple floors and wings. A subnet is one wing of the building: every desk (VM) inside that wing has an address within that wing’s numbering scheme. Two desks in the same wing can talk to each other directly. Two desks in different wings can also talk, but they have different address ranges, and you can put security guards at the door between wings to control exactly who passes.

In GCP, one wing covers the entire floor (region). You do not need a separate wing per corner of the floor (zone). Two VMs in different zones within the same region can share a subnet without any special configuration. This is the most important practical difference from AWS, where each wing only covers one corner of one floor.

Subnet design matters early because you cannot make a wing smaller once you have built it, and the address ranges in one wing cannot overlap with those in any wing you plan to connect later, whether in the same building or in an entirely different building (another VPC or your on-premises network).

What a subnet is in GCP

A subnet is a named, regional IP address range within a VPC network. When you create a VM, you choose which subnet to place it in, and GCP assigns a private IP address from that subnet’s range. The VM holds that IP for its lifetime unless you explicitly reassign it.

The VPC itself is global. It spans all GCP regions and has no IP space of its own. IP addressing comes from the subnets you create within it. Each subnet is attached to exactly one region. A subnet in us-central1 is separate from a subnet in europe-west1, even though both live inside the same VPC.

Within a region, a GCP subnet spans every zone automatically. A VM in us-central1-a and a VM in us-central1-c can both use the same subnet and communicate via private IP. You achieve high availability by spreading VMs across zones within a single regional subnet, not by creating a subnet per zone.

This regional scope is also what makes subnet-level settings so useful. Features like Private Google Access are configured per subnet, so enabling it once covers every zone in that region. You get consistent policy without duplicating configuration per zone.

How subnets work in GCP

At the top level sits your VPC, a global software-defined network with no IP space of its own. When you create a subnet, you specify a region and a CIDR range such as 10.0.1.0/24. That range is now exclusively allocated to that subnet within the VPC. No other subnet in the same VPC can use overlapping addresses.

When a VM is created in that subnet, GCP assigns an available IP from the range and attaches the VM’s network interface to the subnet. The VM now has an internal IP. It can reach other VMs in the same subnet directly. It can also reach VMs in other subnets within the same VPC, because the VPC has system-generated routes that connect all subnets automatically. You do not need to configure routing between subnets yourself.

What you do need to configure is firewall rules, because GCP’s default implicit rule blocks all inbound traffic. Without an explicit allow rule, cross-subnet traffic is denied even though the route exists. Subnets give you the IP segmentation that makes firewall rules meaningful. A rule that allows traffic only from 10.0.1.0/24 (the web subnet) to 10.0.2.0/24 (the app subnet) on port 8080 is readable, auditable, and enforceable at the network level.

It is worth noting that firewall rules in GCP can also target VMs by network tag or service account rather than just subnet CIDR. That flexibility is useful, but subnet boundaries remain the foundation of a clean security design. For a fuller picture of how traffic flows between subnets, see Routes in GCP.

GCP subnets vs AWS subnets

This is the most common source of confusion for engineers moving from AWS to GCP, and it has real architectural consequences that affect how many subnets you need and how you design for high availability.

In AWS, a subnet is tied to a single availability zone. To deploy a highly available application across two zones, you need two subnets: one per zone. A three-tier application in one AWS region with two availability zones typically requires six subnets (web-a, web-b, app-a, app-b, db-a, db-b). Each subnet needs its own route table associations and explicit gateway configuration.

In GCP, a subnet is regional. One web subnet in us-central1 covers us-central1-a, us-central1-b, us-central1-c, and us-central1-f simultaneously. A three-tier application in one GCP region needs three subnets: web, app, and data. Zone redundancy comes from placing VMs in different zones within each subnet, not from creating additional subnets.

AspectGCP subnetsAWS subnets
ScopeRegional (spans all zones)Zonal (one availability zone)
High availability designSpread VMs across zones in one subnetCreate one subnet per AZ per tier
Subnets for a 3-tier HA app3 (one per tier)6 or more (one per tier per AZ)
Route tablesSystem-managed, automatic between subnetsMust be attached and configured per subnet
Internet gateway routeAutomatic system route in the VPCMust be added to each subnet’s route table

The migration mistake is creating per-zone subnets in GCP out of AWS habit. It wastes IP space, multiplies your firewall rule count, and adds zero availability benefit. One regional subnet with VMs spread across zones is the correct GCP pattern.

AWS habit to unlearn

If you find yourself naming subnets web-us-central1-a, web-us-central1-b, and web-us-central1-c, stop. GCP does not need this. One subnet named web-us-central1 already covers all three zones. Per-zone subnets in GCP are unnecessary complexity with no benefit.

Note

GCP managed services benefit from the regional subnet model too. A managed instance group, a GKE node pool, or a Cloud SQL private IP can span multiple zones within a region while drawing from a single subnet. In AWS, equivalent configurations require per-zone subnets and more complex routing.

CIDR and IP range planning

CIDR (Classless Inter-Domain Routing) notation describes a block of IP addresses. A value like 10.0.1.0/24 means the first 24 bits identify the network and the remaining 8 bits identify individual hosts. The number after the slash is called the prefix length.

A smaller prefix number means a larger range. A larger prefix number means a smaller range.

  • /28 — 16 addresses, 11 usable (GCP reserves 4 per subnet)
  • /24 — 256 addresses, 252 usable
  • /22 — 1,024 addresses, 1,020 usable
  • /20 — 4,096 addresses, 4,092 usable
  • /16 — 65,536 addresses

GCP subnets must use private IP ranges defined in RFC 1918:

  • 10.0.0.0/8 — about 16.7 million addresses
  • 172.16.0.0/12 — about 1 million addresses
  • 192.168.0.0/16 — 65,536 addresses
Tip

A practical starting point: allocate 10.0.0.0/16 as your VPC address space, then carve it into /24 subnets per tier and region. That gives you 256 subnets of 252 usable IPs each, with room to expand any of them and no overlap with typical on-premises ranges. Leave visible gaps between subnets (for example, skip 10.0.0.x entirely as padding) so future expansion does not collide with an adjacent subnet.

Warning

GCP reserves four IP addresses in every subnet: the network address, the second address (used as the subnet gateway), the second-to-last address, and the broadcast address. A /29 leaves you only 4 usable IPs for VMs. Avoid very small subnets unless the use case genuinely requires it.

Planning matters far more in GCP than many teams initially realise, because several features require non-overlapping ranges between networks. VPC Peering will not work if the peered VPCs share overlapping CIDR blocks. Shared VPC needs careful range coordination across host and service projects. VPN tunnels and Cloud Interconnect to on-premises networks require that your GCP subnets do not overlap with your on-premises IP space. If your on-premises network uses 10.0.0.0/8 and your GCP subnets also draw from that range, the connection will fail.

Hard lesson

Re-addressing after the fact is painful. You cannot reassign IPs to existing VMs without redeploying them. Subnets cannot shrink. Overlapping ranges with connected networks require dismantling and rebuilding the peering or VPN. Survey your existing IP allocations before you start assigning GCP ranges, and plan generously the first time.

Primary and secondary IP ranges

Every subnet has exactly one primary IP range. That is the range from which VMs get their internal IPs. For most subnets, the primary range is all you need.

A subnet can also have one or more secondary IP ranges. These are additional CIDR blocks attached to the same subnet but used for a different purpose. The most common case is GKE: when you create a GKE cluster in VPC-native mode (the default and recommended mode), the cluster needs IP addresses for pods and for services, separate from the VM IPs on the node.

Pod IPs are assigned from a large secondary range. Each GKE node gets a dedicated block of pod IPs. At the default allocation of a /24 per node, a 50-node cluster needs 12,800 pod IP addresses. A secondary range of /14 gives you around 262,000 addresses and provides adequate room for growth. Service IPs come from a separate secondary range, typically a /20.

# Create a subnet with secondary ranges ready for GKE
gcloud compute networks subnets create gke-subnet \
  --network=production-vpc \
  --region=us-central1 \
  --range=10.0.4.0/22 \
  --secondary-range=pods=10.4.0.0/14 \
  --secondary-range=services=10.0.32.0/20

Secondary ranges must not overlap with the primary range, any other subnet’s primary range, or any other secondary range in the VPC.

Plan ahead for GKE

Reserve secondary ranges now, even if you are not using GKE yet. Finding a non-overlapping /14 in a VPC that has been running for a year is genuinely hard. In a fresh VPC, it takes thirty seconds. Add a —secondary-range flag as a placeholder when creating subnets for workloads that might eventually host GKE nodes.

For a full explanation of how GKE allocates pod and service IPs from these ranges, see the GKE Networking Model.

Note

Secondary ranges are only accessible via alias IP addresses, which is how GKE nodes expose pod IPs on their interfaces. A regular VM cannot use a secondary range for its primary interface. Secondary ranges exist specifically for this alias IP use case.

When to use separate subnets

The primary reason to use separate subnets is to create boundaries you can enforce with firewall rules. If all your VMs share one subnet, you cannot write a rule that prevents your web servers from connecting directly to your database servers. They are all in the same IP range, and a firewall rule targeting a CIDR source requires a distinct CIDR to target.

Common patterns for subnet separation:

  • Web tier. Public-facing VMs that receive traffic from a load balancer or directly from the internet. These need ingress on ports 80 and 443 from external sources, and egress to the app tier on an internal port.
  • Application tier. Business logic VMs that should not be reachable directly from the internet. Placing them in a separate subnet makes it straightforward to write a rule that only allows ingress from the web subnet’s CIDR range.
  • Data tier. Databases, cache instances, and persistent stores. Restrict ingress to the app subnet only. A private IP and a targeted firewall rule is a strong default for any data tier.
  • Internal tooling and build infrastructure. Systems that should never receive internet traffic. A dedicated subnet with no external IPs and Private Google Access enabled is a clean, auditable pattern for CI runners, internal dashboards, and similar workloads.
  • GKE node pools. GKE clusters need dedicated subnets with appropriately sized primary and secondary ranges. Mixing GKE nodes with standard VMs in the same subnet complicates IP planning and risks address exhaustion.
  • Multi-region workloads. Each region requires its own subnets with non-overlapping CIDR ranges, even though they share the same global VPC and can communicate privately without extra configuration.
Keep it simple

A small internal project or a two-layer application often needs only one or two subnets. Creating subnets for every conceivable future workload adds management overhead without proportionate security benefit. Start with the minimum number of subnets that serve real isolation needs, and add more when a genuine access-control boundary is required.

Private Google Access at the subnet level

A VM with no external IP address cannot reach Google APIs such as Cloud Storage, BigQuery, or Pub/Sub by default. It has no route to the public internet, so outbound API calls simply fail. This catches many teams off guard, because removing external IPs is the correct security posture but the follow-up step of enabling Private Google Access is easy to overlook.

Private Google Access is a per-subnet flag. When enabled, VMs in that subnet can reach Google APIs via an internal path on Google’s network, without needing a public IP or a Cloud NAT gateway. The traffic never touches the public internet. It is a clean solution for internal workloads that need access to GCP services.

# Enable Private Google Access on an existing subnet
gcloud compute networks subnets update web-subnet \
  --region=us-central1 \
  --enable-private-ip-google-access

# Enable it at creation time
gcloud compute networks subnets create app-subnet \
  --network=production-vpc \
  --region=us-central1 \
  --range=10.0.2.0/24 \
  --enable-private-ip-google-access
Easy to forget

Forgetting Private Google Access produces confusing timeout errors when a VM tries to call a GCP API, rather than a clear permission error. Enable it on every internal subnet at creation time. It takes one extra flag and saves a frustrating debugging session later.

Private Google Access only covers GCP-managed services. It does not provide general internet access. For VMs that also need to reach non-Google destinations such as package repositories or third-party APIs, add Cloud NAT. The two work together and serve different outbound paths. See Private Google Access for the full explanation, including DNS configuration and behaviour under VPC Service Controls.

Creating and managing subnets

Subnets are created as part of a custom mode VPC. Custom mode gives you full control over which regions have subnets and what ranges they use. Auto mode creates subnets in every region automatically with fixed ranges, which causes peering conflicts later. See Default vs Custom Networks for why custom mode is the right starting point for any production environment.

# Create a custom mode VPC first
gcloud compute networks create production-vpc \
  --subnet-mode=custom

# Create a web-tier subnet in us-central1
gcloud compute networks subnets create web-subnet \
  --network=production-vpc \
  --region=us-central1 \
  --range=10.0.1.0/24 \
  --enable-private-ip-google-access

# Create an app-tier subnet in the same region
gcloud compute networks subnets create app-subnet \
  --network=production-vpc \
  --region=us-central1 \
  --range=10.0.2.0/24 \
  --enable-private-ip-google-access

# Create a subnet in a second region
gcloud compute networks subnets create web-subnet-eu \
  --network=production-vpc \
  --region=europe-west1 \
  --range=10.1.1.0/24 \
  --enable-private-ip-google-access
# List all subnets in a network
gcloud compute networks subnets list --network=production-vpc

# Describe a specific subnet
gcloud compute networks subnets describe web-subnet \
  --region=us-central1

To expand a subnet, the new range must be a superset of the existing one and must not overlap with other subnets in the VPC:

# Expand 10.0.1.0/24 to 10.0.0.0/23 (which contains the original /24)
gcloud compute networks subnets expand-ip-range web-subnet \
  --region=us-central1 \
  --prefix-length=23

You cannot shrink a subnet. If a range is too large, the only path is to remove all resources from the subnet, delete it, and recreate it with the correct range. Getting the size right the first time is always simpler.

Common mistakes

  1. Creating per-zone subnets out of AWS habit. GCP subnets are regional. Creating one subnet per zone wastes IP space, multiplies firewall rule complexity, and provides no availability benefit. Use one regional subnet per tier, and spread VMs across zones within it.
  2. Putting everything in one large subnet. A single /16 for all workloads removes your ability to enforce tier-level isolation with firewall rules. Web servers, application servers, and databases should live in separate subnets so access policies can be expressed at the network boundary.
  3. Overlapping ranges with on-premises or peered networks. If your on-premises network uses 10.0.0.0/8 and your GCP subnets draw from the same range, VPN and Interconnect connections will fail to route. Survey all existing IP allocations before assigning GCP subnet ranges. This is one of the most painful mistakes to undo in a live environment.
  4. Forgetting Private Google Access on internal subnets. VMs without external IPs cannot reach Cloud Storage, BigQuery, or other GCP APIs unless Private Google Access is enabled on their subnet. The failure mode is a timeout with no obvious cause. Enable it by default at subnet creation time for all internal subnets.
  5. Poor secondary range planning for GKE. GKE pod ranges in VPC-native clusters are large. A cluster with 100 nodes at the default /24 per node needs at least 25,600 pod IPs. If you have not reserved a /14 or similar secondary range before the VPC fills up, you will need to re-plan the entire IP scheme when GKE is introduced.
  6. Subnet sizes that are too small. A /28 has 11 usable IPs. GCP managed services consume IPs from subnets: Cloud SQL private IPs, internal load balancers, and GKE nodes all take addresses from the primary range. Running out of IPs requires expanding the subnet, which is only possible if adjacent ranges are free.

Practical design example

Here is a concrete subnet plan for a production application running in two GCP regions, designed to stay peerable, extensible, and secure by default.

VPC: production-vpc, custom mode. IP space drawn from 10.0.0.0/8, with 10.0.x.x reserved for the primary region and 10.1.x.x for the secondary region.

us-central1 subnets:

  • web-us at 10.0.1.0/24: public-facing VMs behind a load balancer. Private Google Access enabled.
  • app-us at 10.0.2.0/24: application logic VMs, no external IPs. Private Google Access enabled.
  • data-us at 10.0.3.0/24: Cloud SQL private IPs and Memorystore. No external IPs. Private Google Access enabled.
  • gke-us at 10.0.4.0/22: GKE node pool. Secondary ranges reserved: pods at 10.4.0.0/14, services at 10.0.32.0/20. Private Google Access enabled.

europe-west1 subnets:

  • web-eu at 10.1.1.0/24, app-eu at 10.1.2.0/24, data-eu at 10.1.3.0/24: same tier structure, different address block.

Because 10.0.x and 10.1.x do not overlap, adding a future peered development VPC at 10.2.0.0/16 is straightforward. Connecting an on-premises network works cleanly provided on-premises uses a different range such as 172.16.0.0/12.

Firewall rules restrict the data subnet to receive ingress only from the app subnet. The web subnet accepts TCP 80 and 443 from the internet. The app subnet accepts ingress only from the web subnet. Adding VPC Peering or a Cloud Interconnect later requires no re-addressing, because ranges were planned with expansion in mind.

This is not a complex design. It is a small number of well-scoped subnets with clear purposes, enough IP headroom to grow, and Private Google Access enabled throughout. That combination covers the vast majority of real production workloads without unnecessary fragmentation.

Frequently asked questions

Are GCP subnets regional or zonal?

GCP subnets are regional. A single subnet spans all zones within a region. A VM in us-central1-a and a VM in us-central1-b can both use the same subnet and communicate using private IPs from that subnet's range. You do not need separate subnets per zone. This is one of the most important differences from AWS, where every subnet is tied to a single availability zone.

How do I choose a subnet size in GCP?

Start by estimating the maximum number of resources you expect in the subnet, then round up generously. A /24 gives 252 usable IPs and suits small workloads. A /22 gives around 1,020 and works well for general-purpose subnets. A /20 gives around 4,092. If the subnet will host a GKE node pool, budget additional space for secondary ranges: typically a /14 for pods and a /20 for services. Err on the side of generosity because you cannot shrink a subnet after creation.

Can I expand or shrink a subnet after creation?

You can expand a subnet's primary IP range after creation, as long as the new range is a superset of the existing one and does not overlap with other subnets in the VPC. For example, 10.0.1.0/24 can be expanded to 10.0.0.0/23. You cannot shrink a subnet once it is set. The only way to reduce a subnet range is to delete it entirely and recreate it, which requires removing all resources from the subnet first.

What are secondary IP ranges used for?

Secondary IP ranges are additional CIDR blocks attached to a subnet for a different purpose than the primary range. GKE uses them for pod IP addresses and service IP addresses, keeping those separate from VM IPs. Secondary ranges must not overlap with the primary range or any other range in the VPC. Plan for them early, because finding large non-overlapping blocks in a densely packed VPC later is significantly harder.

Do I need a different subnet for each GCP zone?

No. GCP subnets are regional, not zonal. One subnet in us-central1 covers us-central1-a, us-central1-b, and us-central1-c simultaneously. For high availability, spread VMs across zones within a single regional subnet by specifying the zone flag when creating each VM. Creating a separate subnet per zone adds unnecessary complexity and wastes IP space.

Last verified: 24 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.