DEV Community

Cover image for GCP Defaults Every VM to Premium Network and You're Paying 40% More for Egress You Don't Need 🌐
Suhas Mallesh
Suhas Mallesh

Posted on

GCP Defaults Every VM to Premium Network and You're Paying 40% More for Egress You Don't Need 🌐

GCP has two network tiers: Premium ($0.12/GB) and Standard ($0.085/GB). Premium routes traffic over Google's private backbone. Standard uses the public internet. The catch? Premium is the default for every resource you create. Your dev VMs, staging APIs, internal tools - all paying premium egress rates for traffic that doesn't need Google's backbone. Switch non-critical workloads to Standard Tier and save 30-45% on egress instantly.

Most teams don't even know GCP has network tiers. They create resources, traffic flows, and the egress line item on their bill grows silently. For a workload doing 5 TB of egress per month in North America, the difference between Premium and Standard is roughly $225/month - just from one config change.

And that's before we add Cloud CDN, which can cut egress costs by another 60-80% for cacheable content.

Let's fix both with Terraform.

šŸ“Š The Egress Pricing Cheat Sheet

Premium Tier (default):

Monthly Volume North America Europe Asia
0-1 TB $0.12/GB $0.12/GB $0.12/GB
1-10 TB $0.11/GB $0.11/GB $0.11/GB
10+ TB $0.08/GB $0.08/GB $0.08/GB

Standard Tier (opt-in):

Monthly Volume North America Europe Asia
0-1 TB $0.085/GB $0.085/GB $0.11/GB
1-10 TB $0.065/GB $0.065/GB $0.095/GB
10+ TB $0.045/GB $0.045/GB $0.065/GB

Side-by-side for 5 TB/month (North America):

Tier Cost Savings
Premium ~$570 baseline
Standard ~$345 $225/month (39% saved)
Standard + Cloud CDN (70% cache hit) ~$135 $435/month (76% saved)

āš ļø Important tradeoff: Standard Tier routes traffic via the public internet. Latency is 50-100ms higher for users far from your GCP region. This matters for real-time apps serving global users. It does NOT matter for dev/staging, internal tools, B2B APIs, or batch workloads.

šŸ”§ Step 1: Set Standard Tier as Project Default for Non-Prod

Set the default network tier at the project level so every new resource in that project uses Standard automatically:

# Set Standard Tier as the default for non-prod projects
resource "google_compute_project_default_network_tier" "default" {
  project      = var.project_id
  network_tier = var.environment == "prod" ? "PREMIUM" : "STANDARD"
}
Enter fullscreen mode Exit fullscreen mode

This one resource changes the default for every new external IP, forwarding rule, and instance in the project. Existing resources are not affected - only new ones.

āš ļø Gotcha: Standard Tier does NOT support global load balancing, Cloud CDN, or anycast IPs. If you need any of these features, use Premium Tier for those specific resources. You can mix tiers within the same project.

šŸ–„ļø Step 2: Per-Resource Network Tier Control

For finer control, set the network tier on individual resources:

# Production: Premium Tier for user-facing APIs
resource "google_compute_instance" "prod_api" {
  name         = "prod-api"
  machine_type = "e2-custom-4-8192"
  zone         = var.zone

  network_interface {
    network    = var.network_id
    subnetwork = var.subnet_id

    access_config {
      network_tier = "PREMIUM"  # Global backbone for end users
    }
  }

  labels = merge(local.common_labels, {
    network-tier = "premium"
  })
}

# Dev/Staging: Standard Tier saves 30-45%
resource "google_compute_instance" "staging_api" {
  name         = "staging-api"
  machine_type = "e2-custom-2-4096"
  zone         = var.zone

  network_interface {
    network    = var.network_id
    subnetwork = var.subnet_id

    access_config {
      network_tier = "STANDARD"  # Public internet, 30-45% cheaper
    }
  }

  labels = merge(local.common_labels, {
    network-tier = "standard"
  })
}
Enter fullscreen mode Exit fullscreen mode

Decision matrix for which tier to use:

Workload Tier Why
User-facing production APIs Premium Latency matters for UX
Dev/staging environments Standard Nobody notices 50ms more
Internal tools and dashboards Standard Used by employees only
B2B APIs with known clients Standard Clients have stable connections
Batch data processing Standard Latency is irrelevant
Global consumer apps Premium Users worldwide need low latency
CI/CD runners Standard Build artifacts don't need backbone

šŸš€ Step 3: Cloud CDN for Static Assets

Cloud CDN caches content at Google's edge locations worldwide. Cache hits are served from the nearest edge, dramatically reducing origin egress:

# Backend bucket pointing to Cloud Storage
resource "google_compute_backend_bucket" "cdn_assets" {
  name        = "cdn-static-assets"
  bucket_name = google_storage_bucket.static_assets.name
  enable_cdn  = true

  cdn_policy {
    cache_mode        = "CACHE_ALL_STATIC"
    default_ttl       = 3600     # 1 hour default
    max_ttl           = 86400    # 24 hours max
    client_ttl        = 3600
    serve_while_stale = 86400    # Serve stale for 24hr if origin is down

    cache_key_policy {
      include_http_headers = []
    }
  }
}

# GCS bucket for static content
resource "google_storage_bucket" "static_assets" {
  name     = "${var.project_id}-static-assets"
  location = "US"

  uniform_bucket_level_access = true
  labels                      = local.common_labels
}

# Make objects publicly readable for CDN
resource "google_storage_bucket_iam_member" "public_read" {
  bucket = google_storage_bucket.static_assets.name
  role   = "roles/storage.objectViewer"
  member = "allUsers"
}

# URL map
resource "google_compute_url_map" "cdn" {
  name            = "cdn-url-map"
  default_service = google_compute_backend_bucket.cdn_assets.id
}

# HTTPS proxy
resource "google_compute_target_https_proxy" "cdn" {
  name             = "cdn-https-proxy"
  url_map          = google_compute_url_map.cdn.id
  ssl_certificates = [var.ssl_certificate_id]
}

# Global forwarding rule (requires Premium Tier)
resource "google_compute_global_forwarding_rule" "cdn" {
  name       = "cdn-forwarding-rule"
  target     = google_compute_target_https_proxy.cdn.id
  port_range = "443"
  ip_protocol = "TCP"
}
Enter fullscreen mode Exit fullscreen mode

Cost comparison for serving 2 TB/month of static assets (North America):

Method Cost
Direct from GCS (Premium egress) ~$240/month
Direct from GCS (Standard egress) ~$170/month
Cloud CDN (70% cache hit rate) ~$85/month
Cloud CDN (90% cache hit rate) ~$50/month

That's $190/month saved with Cloud CDN at 70% cache hit rate vs direct GCS. Cache hit rates for static assets (images, CSS, JS) routinely hit 85-95%.

āš ļø Cloud CDN requires Premium Tier for the forwarding rule. But the CDN cache egress rate ($0.08/GB for North America) is cheaper than both Premium and Standard direct egress. So you pay Premium for the infrastructure but get lower per-GB rates from the cache.

šŸ”’ Step 4: Private Google Access (Free Savings)

VMs without external IPs that need to reach Google APIs (Cloud Storage, BigQuery, etc.) normally route through Cloud NAT, which charges $0.045/GB processing. Private Google Access lets them reach Google APIs directly at zero cost:

resource "google_compute_subnetwork" "private" {
  name          = "private-subnet"
  ip_cidr_range = "10.0.1.0/24"
  region        = var.region
  network       = var.network_id

  # This one flag saves $0.045/GB on all Google API traffic
  private_ip_google_access = true  # šŸ‘ˆ Free, enable everywhere
}
Enter fullscreen mode Exit fullscreen mode

This costs nothing to enable and immediately eliminates NAT processing charges for Google API traffic. Every subnet should have this turned on.

Savings for 500 GB/month of Google API traffic from private VMs:

Route Cost
Via Cloud NAT $22.50/month ($0.045/GB)
Via Private Google Access $0/month

šŸ¢ Step 5: Cross-Region Traffic Audit

Same-region traffic between GCP services is usually free. Cross-region traffic costs $0.01/GB. This adds up when services are accidentally deployed in different regions:

# Ensure all resources are in the same region
variable "region" {
  type        = string
  default     = "us-central1"
  description = "Primary region - keep everything here to avoid cross-region egress"
}

# Validate that storage and compute are co-located
resource "google_storage_bucket" "data" {
  name     = "${var.project_id}-data"
  location = var.region  # Same region as compute!
  labels   = local.common_labels
}

resource "google_compute_instance" "worker" {
  name         = "data-worker"
  machine_type = "e2-custom-4-8192"
  zone         = "${var.region}-a"  # Same region as storage!
  # ...
}
Enter fullscreen mode Exit fullscreen mode

āš ļø Common mistake: Creating a Cloud Storage bucket with location = "US" (multi-region) and compute in us-central1 (single region). Traffic between them may incur cross-region charges. For cost optimization, use the same single region for both.

šŸ’” Quick Reference: What to Do First

Action Effort Savings
Set Standard Tier default for non-prod projects 5 min 30-45% on non-prod egress
Enable Private Google Access on all subnets 5 min $0.045/GB on Google API traffic
Switch dev/staging VMs to Standard Tier 10 min 30-45% per VM egress
Add Cloud CDN for static assets 20 min 60-80% on cacheable content
Audit cross-region resource placement 15 min Eliminate $0.01/GB cross-region fees
Remove external IPs from internal-only VMs 10 min Eliminates accidental egress

Start with Private Google Access. It's one line in Terraform, costs $0, and starts saving immediately. šŸŽÆ

šŸ“Š TL;DR

Premium Tier (default)       = $0.12/GB, Google backbone, low latency
Standard Tier (opt-in)       = $0.085/GB, public internet, 30-45% cheaper
Project default tier         = one resource changes all new instances
Per-resource override        = mix Premium (prod) and Standard (dev)
Cloud CDN                    = cache at edge, 60-80% less origin egress
Cloud CDN requires Premium   = but cache egress is cheaper than both tiers
Private Google Access        = free, eliminates NAT charges for API traffic
Same-region traffic          = free between most GCP services
Cross-region traffic         = $0.01/GB, avoid by co-locating resources
Internal IP vs external IP   = same-zone traffic is free only with internal
Enter fullscreen mode Exit fullscreen mode

Bottom line: GCP defaults everything to Premium Tier, and most teams never change it. Switching non-critical workloads to Standard saves 30-45% on egress. Adding Cloud CDN saves another 60-80% on cacheable content. Enabling Private Google Access is free and immediate. Combined, these three moves can cut your networking bill by 70%+. 🌐


Go check your non-prod projects right now. If they're still on Premium Tier, you're paying a 40% markup for network performance that literally nobody notices on a staging server. One Terraform resource fixes it. šŸ˜€

Found this helpful? Follow for more GCP cost optimization with Terraform! šŸ’¬

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.