Google Cloud's VPC implementation is the most flexible of the major clouds: subnets are regional (one subnet spans all zones in a region), only 4 IPs are reserved per subnet instead of AWS's 5, and subnet expansion is supported online without recreating resources. These design choices come from Google's experience running global infrastructure, and they meaningfully simplify multi-zone architectures.
This article covers how GCP VPC sizing differs from AWS and Azure, the standard production patterns, and the gotchas to watch for.
The big architectural difference: regional subnets
In AWS, each subnet is bound to a single AZ. A three-AZ deployment needs three subnets per tier. In GCP, one subnet covers all zones in a region. A three-zone deployment uses one subnet — the platform handles per-zone IP assignment.
This simplifies VPC layouts dramatically. A typical GCP production VPC with three tiers:
my-vpc (custom mode) +-- web-tier-us-central1 10.10.0.0/20 (4,092 usable) +-- app-tier-us-central1 10.10.16.0/20 (4,092 usable) +-- db-tier-us-central1 10.10.32.0/24 (252 usable) +-- web-tier-europe-west1 10.20.0.0/20 (different region) +-- app-tier-europe-west1 10.20.16.0/20 +-- db-tier-europe-west1 10.20.32.0/24
Six subnets total, not 18 (three AZs × six tiers × two regions would be the AWS count). The simplification compounds as you add more regions and tiers.
Only 4 reserved IPs
| Address | Purpose |
|---|---|
| .0 | Network address |
| .1 | Default gateway |
| second-to-last | Reserved by Google for future use |
| last | Broadcast address |
One fewer reservation than AWS or Azure. A GCP /28 gives 12 usable addresses; a /24 gives 252.
Minimum subnet: /29
GCP allows subnets as small as /29 (8 total, 4 usable). Practical minimum for any real workload is /28 or /27.
Auto-mode vs custom-mode VPCs
GCP supports two VPC types:
| Mode | Behavior | Recommendation |
|---|---|---|
| Auto-mode | Subnets pre-created in every region, fixed CIDRs (10.128.0.0/9) | Tutorials and demos only |
| Custom-mode | You define every subnet manually | Always for production |
Auto-mode VPCs are convenient for getting started but use fixed CIDRs in 10.128.0.0/9. If you have any on-premises networks or other clouds that might conflict, auto-mode creates instant overlap problems. Always use custom-mode for production.
Subnet expansion (the killer feature)
This is the operational advantage GCP has over AWS and Azure. You can expand a subnet's CIDR online without affecting running workloads.
# Before: 10.10.0.0/24 (running with 50 instances) gcloud compute networks subnets expand-ip-range my-subnet \ --region=us-central1 \ --prefix-length=22 # After: 10.10.0.0/22 (4x larger, no instance restarts needed)
The only constraint is that the new range must:
- Contain the original range (you can grow, not move)
- Not overlap any other subnet in the VPC
- Not exceed /16 (subnet max)
This makes "oh no we ran out of IPs" recoverable without re-IPing or maintenance windows. Compare to AWS where the only fix is adding a secondary VPC CIDR or re-IPing workloads.
Secondary IP ranges
Each GCP subnet can have multiple secondary IP ranges that are used by specific services. The most important use case is GKE (Google Kubernetes Engine) clusters, which use secondary ranges for:
- Pod IP range — typically /16 or /17, providing addresses for every pod
- Service IP range — typically /20, virtual addresses for Services
Example: a primary subnet of 10.10.0.0/22 for nodes, with secondary 10.40.0.0/14 for pods and 10.50.0.0/20 for services. The pod range can be much larger than the node range without consuming VM-routable space.
Shared VPC (the GCP-specific pattern)
GCP has a powerful concept called Shared VPC: one host project owns the VPC, multiple service projects deploy resources into it. This is the GCP equivalent of AWS VPC peering or Transit Gateway, but tighter — service project resources see the shared VPC as if it were their own.
For multi-team organizations, the pattern is:
- Create one host project with all VPCs and subnets
- Network team manages CIDR allocation and routing
- Each application team gets a service project with permission to deploy into specific subnets
- No peering, no Transit Gateway — just access controls
This is meaningfully simpler than the AWS hub-and-spoke pattern using Transit Gateway.
Global routing as default
GCP VPCs have global routing by default: a VM in us-central1 can reach a VM in europe-west1 using the same VPC's subnets without any peering setup. This is in stark contrast to AWS, where VPCs are regional and cross-region traffic requires peering or Transit Gateway.
The downside: cross-region traffic crosses Google's backbone but is still subject to network egress charges. Design with regional separation in mind for cost optimization.
Standard production layout
prod-vpc (custom-mode, global) +-- web-us-central1 10.10.0.0/20 (4,092 usable) +-- app-us-central1 10.10.16.0/20 (4,092 usable) +-- db-us-central1 10.10.32.0/24 (252 usable) +-- gke-nodes-us-cent1 10.10.36.0/22 (1,020 usable) | +-- (secondary) pods 10.40.0.0/14 (262,140) | +-- (secondary) services 10.50.0.0/20 (4,092) +-- web-europe-west1 10.20.0.0/20 +-- app-europe-west1 10.20.16.0/20 +-- db-europe-west1 10.20.32.0/24
Compare to the AWS equivalent — same workload would require ~24 subnets across two regions. GCP's regional subnet model reduces VPC complexity by ~3x.
Terraform pattern
resource "google_compute_network" "prod" {
name = "prod-vpc"
auto_create_subnetworks = false # always custom mode
routing_mode = "GLOBAL"
}
resource "google_compute_subnetwork" "gke_nodes" {
name = "gke-nodes-us-central1"
region = "us-central1"
network = google_compute_network.prod.id
ip_cidr_range = "10.10.36.0/22"
secondary_ip_range {
range_name = "pods"
ip_cidr_range = "10.40.0.0/14"
}
secondary_ip_range {
range_name = "services"
ip_cidr_range = "10.50.0.0/20"
}
}
Our IaC Export generates this for GCP with the standard tiered subnet layout and GKE secondary ranges.
Common GCP subnet mistakes
- Using auto-mode in production. CIDR conflicts with on-prem are almost guaranteed eventually. Always start custom-mode.
- Sizing GKE secondary ranges too small. Like all Kubernetes, pod CIDR is fixed at cluster creation. See our Kubernetes CIDR sizing article.
- Not using subnet expansion. Many engineers default to AWS-style "recreate the subnet" thinking. GCP supports online expansion — use it.
- Forgetting global routing. A VM in another region can reach your DB by default. Lock this down with firewall rules if you want regional isolation.
Key takeaways
- GCP subnets are regional, not zonal — one subnet per region per tier, not per AZ.
- Only 4 IPs reserved per subnet (vs 5 for AWS/Azure).
- Online subnet expansion is supported and is the killer feature for capacity planning.
- Always use custom-mode VPCs in production; auto-mode is for tutorials only.
- GKE uses secondary IP ranges for pods and services within a subnet — size these carefully because they cannot be resized after cluster creation.
- Shared VPC is the GCP-specific pattern for multi-team architectures — simpler than AWS hub-and-spoke.