hashicorp/google ~> 6.0) lets you define VPC networks, Compute Engine VMs, Cloud Storage, Cloud SQL, and IAM as code.terraform init && terraform plan && terraform applygoogle_project_service to enable APIs declaratively.~> constraint.| Resource | Terraform Type | Key Arguments | Notes |
|---|---|---|---|
| VPC Network | google_compute_network | name, auto_create_subnetworks | Set false for custom |
| Subnet | google_compute_subnetwork | network, ip_cidr_range, region | One per region |
| Firewall Rule | google_compute_firewall | network, allow, source_ranges | Network-level |
| Compute Instance | google_compute_instance | machine_type, zone, boot_disk | Use data source for image |
| Cloud Storage | google_storage_bucket | name, location, storage_class | Globally unique name |
| Cloud SQL | google_sql_database_instance | database_version, settings.tier | Private IP with VPC peering |
| IAM Binding | google_project_iam_member | role, member | Use member for additive |
| Service Account | google_service_account | account_id | One per service |
| Cloud NAT | google_compute_router_nat | router, nat_ip_allocate_option | Private subnet egress |
| API Enablement | google_project_service | service | Enable APIs declaratively |
| GCS Backend | backend "gcs" | bucket, prefix | Native locking |
START
├── First time with Terraform on GCP?
│ ├── YES → Enable APIs + GCS backend (Step 1-2)
│ └── NO ↓
├── Need full VPC with private/public subnets?
│ ├── YES → Custom VPC + Cloud NAT (Step 3)
│ └── NO ↓
├── Need VMs or containers?
│ ├── VMs → Compute Engine (Step 4)
│ ├── Containers → Cloud Run or GKE
│ └── NO ↓
├── Need managed database?
│ ├── YES → Cloud SQL with private IP
│ └── NO ↓
└── DEFAULT → VPC + Compute Engine + Cloud Storage
Set up the Google provider and enable APIs. [src1]
terraform {
required_version = ">= 1.6.0"
required_providers {
google = { source = "hashicorp/google", version = "~> 6.0" }
}
backend "gcs" {
bucket = "my-project-tf-state"
prefix = "prod"
}
}
provider "google" {
project = var.project_id
region = var.region
}
resource "google_project_service" "apis" {
for_each = toset(["compute.googleapis.com", "sqladmin.googleapis.com", "storage.googleapis.com"])
service = each.value
disable_on_destroy = false
}
Verify: terraform init → backend configured
Custom-mode VPC. [src5]
resource "google_compute_network" "main" {
name = "${var.project_name}-vpc"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "public" {
name = "${var.project_name}-public"
ip_cidr_range = "10.0.1.0/24"
region = var.region
network = google_compute_network.main.id
}
Verify: terraform plan → shows network resources
Deploy a VM. [src2]
data "google_compute_image" "debian" {
family = "debian-12"
project = "debian-cloud"
}
resource "google_compute_instance" "web" {
name = "${var.project_name}-web"
machine_type = "e2-micro"
zone = "${var.region}-a"
boot_disk {
initialize_params { image = data.google_compute_image.debian.self_link }
}
network_interface {
subnetwork = google_compute_subnetwork.public.id
access_config {}
}
tags = ["web", "ssh"]
}
Verify: terraform apply → instance running
# Input: Terraform configuration
# Output: Cloud SQL PostgreSQL with private VPC peering
resource "google_compute_global_address" "private_ip" {
name = "private-ip-range"
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = google_compute_network.main.id
}
resource "google_sql_database_instance" "main" {
name = "${var.project_name}-db"
database_version = "POSTGRES_16"
region = var.region
settings {
tier = "db-f1-micro"
ip_configuration {
ipv4_enabled = false
private_network = google_compute_network.main.id
}
backup_configuration { enabled = true; start_time = "03:00" }
}
deletion_protection = var.environment == "prod"
}
# Input: Domain name
# Output: Cloud Storage + HTTP(S) Load Balancer with CDN
resource "google_storage_bucket" "website" {
name = var.domain_name
location = "US"
website {
main_page_suffix = "index.html"
not_found_page = "404.html"
}
uniform_bucket_level_access = true
}
resource "google_compute_backend_bucket" "website" {
name = "${var.project_name}-backend"
bucket_name = google_storage_bucket.website.name
enable_cdn = true
}
# ❌ BAD — permissive firewall rules
resource "google_compute_instance" "web" {
network_interface { network = "default" }
}
# ✅ GOOD — isolated network
resource "google_compute_network" "main" {
name = "my-vpc"
auto_create_subnetworks = false
}
resource "google_compute_instance" "web" {
network_interface { subnetwork = google_compute_subnetwork.public.id }
}
# ❌ BAD — "API not enabled" error
resource "google_compute_instance" "web" { ... }
# ✅ GOOD — API enabled first
resource "google_project_service" "compute" {
service = "compute.googleapis.com"
disable_on_destroy = false
}
resource "google_compute_instance" "web" {
depends_on = [google_project_service.compute]
}
# ❌ BAD — excessive permissions
role = "roles/owner"
# ✅ GOOD — specific roles
for_each = toset(["roles/compute.admin", "roles/storage.admin"])
google_project_service with disable_on_destroy = false. [src6]false. [src2]google_project_iam_member. [src7]# Initialize providers
terraform init
# Preview changes
terraform plan -out=tfplan
# Apply plan
terraform apply tfplan
# List state
terraform state list
# Check enabled APIs
gcloud services list --enabled --project=PROJECT_ID
# List VMs
gcloud compute instances list --project=PROJECT_ID
| Version | Status | Breaking Changes | Migration Notes |
|---|---|---|---|
| Terraform 1.9+ | Current | None | HCL improvements |
| Google Provider 6.x | Current | Removed deprecated resources | Check migration guide |
| Google Provider 5.x | Supported | Default labels | — |
| OpenTofu 1.6+ | Active | Fork of TF 1.6 | Drop-in compatible |
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Reproducible GCP infrastructure | One-off gcloud commands | gcloud CLI |
| Team collaboration with reviews | Rapid prototyping | GCP Console |
| Multi-cloud deployments | GCP-only with DM expertise | Deployment Manager |
| Long-lived infra (VPCs, Cloud SQL) | K8s resource management | Config Connector, Helm |
google and google-beta providers are separate — beta features require the beta provider.terraform force-unlock.google_project_iam_binding is authoritative — use google_project_iam_member for additive bindings.