Terraform provides a declarative way to create, configure and manage Google Cloud Platform projects and the resources that live inside them. When applied to GCP, Terraform configurations let teams codify project identity, billing association, network topology, service enablement and IAM boundaries in version controlled files. The patterns below reflect how projects are created with Terraform, which permissions are required, how state is managed and where opinionated modules add structure around the core google_project resource.
Module Capabilities for GCP Project Provisioning
A Terraform module focused on GCP project creation can be used to standardize how new projects are brought up across organizations. By default, one reference implementation creates the following regional resources as part of a project bring-up:
- a GCP project with a randomized but memorable project ID and name
- a new project service account, replacing the default account
- a Terraform state bucket in the host project for the project's state
- a KMS keyring and encryption key for asymmetric encryption/decryption
- a GCS bucket for logging access to the project storage bucket, with encryption enabled using the project's KMS key
- a GCS bucket for project-wide storage of sensitive objects, with encryption enabled using the project's KMS key
- a VPC network configured as a service network on the Shared VPC host network
- a default firewall rule blocking SSH from anywhere but inside of GCP Cloud Console
Only the GCP project itself and the service account are required. The additional resources are optional conveniences that enforce encryption, logging and network isolation from day one.
| Resource Category | Example Artifact | Purpose |
|---|---|---|
| Identity | GCP project with randomized memorable project ID | Unique project identity |
| Identity | Project service account | Replaces default account for workloads |
| State | Terraform state bucket in host project | Remote state storage |
| Security | KMS keyring and encryption key | Asymmetric encryption/decryption |
| Storage | GCS bucket for logging access | Audit log retention with encryption |
| Storage | GCS bucket for sensitive objects | Central secure object storage |
| Network | VPC network as service network | Shared VPC connectivity |
| Network | Default firewall rule | SSH restricted to Cloud Console |
Prerequisites and Provider Setup
Before any Terraform code can provision GCP infrastructure, the local environment must satisfy provider prerequisites. Terraform can manage a wide variety of resources using providers. You will build infrastructure on Google Cloud Platform for this tutorial, but Terraform can manage a wide variety of resources using providers. You can find more examples in the use cases section.
The minimum local tooling commonly referenced is:
- The gcloud CLI installed locally
- Terraform 1.2.0+ installed locally
The tutorial is also available as an interactive tutorial within Google Cloud Shell. If you prefer, you can follow this tutorial in Google Cloud Shell.
Provider configuration for GCP requires enabling APIs for the target project. After creating your GCP account, create or modify the following resources to enable Terraform to provision your infrastructure:
Google Compute Engine: Enable the Google Compute Engine API for your project in the GCP console. Make sure to select the project you are using to follow this tutorial and click the "Enable" button.
The set of files used to describe infrastructure in Terraform is known as a Terraform configuration. You will now write your first configuration to create a network.
Each Terraform configuration must be in its own working directory.
A typical first configuration provisions a network and a Linux virtual machine. You will also learn about remote backends, input and output variables, and how to configure resource dependencies. These are the building blocks for more complex configurations.
When Terraform created this network, it also gathered its metadata from the Google provider and recorded it in the state file. Later, you will modify your configuration to reference these values to configure other resources or outputs.
Service Account Permissions and IAM Requirements
Creating projects with Terraform requires a service account with specific IAM roles. Your Terraform service account needs:
- roles/resourcemanager.projectCreator on the organization or folder
- roles/billing.user on the billing account
- roles/resourcemanager.folderAdmin if you are creating projects inside folders
These permissions allow project creation, billing association and folder placement without granting broader organization access.
Project Creation Patterns
A basic project can be defined with the google_project resource. Project IDs must be globally unique, so add a random suffix.
```hcl
resource "googleproject" "project" {
name = "My Application - ${var.environment}"
projectid = "my-app-${var.environment}-${randomid.projectsuffix.hex}"
orgid = var.orgid
billingaccount = var.billingaccountid
autocreatenetwork = false
labels = {
environment = var.environment
team = var.teamname
managed_by = "terraform"
}
}
resource "randomid" "projectsuffix" {
byte_length = 2
}
```
Most organizations use folders to group projects by team, business unit, or environment.
hcl
resource "google_project" "team_project" {
name = "${var.team_name} - ${var.environment}"
project_id = "${var.team_name}-${var.environment}-${random_id.project_suffix.hex}"
folder_id = var.folder_id
billing_account = var.billing_account_id
auto_create_network = false
labels = {
environment = var.environment
team = var.team_name
cost_center = var.cost_center
}
}
A fresh project has almost no APIs enabled. API enablement is a separate step after project creation, typically using google_project_service.
API Enablement and Resource Imports
Importing existing resources into Terraform gives Terraform control over their lifecycle. When you import a resource, Terraform generates a state entry for it, allowing you to manage its lifecycle using your Terraform configuration.
Terraform context: This is achieved using the terraform import command, or by utilizing import blocks introduced in Terraform 1.5+.
Purpose: To gain control over resources that were not initially provisioned by Terraform.
Example CLI import:
bash
terraform import google_compute_instance.my_instance projects/your-gcp-project-id/zones/us-central1-a/instances/my-vm
Addressing concerns about private APIs such as dataproc-control.googleapis.com for Managed Service for Apache Spark:
Customers sometimes encounter references to private APIs in logs or documentation and wonder if they need to enable or import them with Terraform.
No Customer Action Required: If an API is identified as a private or internal Google Cloud API, you don't need to explicitly enable it using googleprojectservice or attempt to import it with Terraform.
Internal Management: These APIs are crucial for the internal operation of Google Cloud services.
State Management and Remote Backends
Terraform execution plans describe the actions to be taken. Terraform will print output similar to what is shown below. We have truncated some of the output for brevity.
```
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions
are indicated with the following symbols:
+ create
Terraform will perform the following actions:
googlecomputenetwork.vpc_network will be created
- resource "googlecomputenetwork" "vpc_network" {
- autocreatesubnetworks = true
- deletedefaultroutesoncreate = false
- gateway_ipv4 = (known after apply)
- id = (known after apply)
- internalipv6range = (known after apply)
- mtu = (known after apply)
- name = "terraform-network"
- networkfirewallpolicyenforcementorder = "AFTERCLASSICFIREWALL"
- numeric_id = "1234567890123456789"
- project = (known after apply)
- routing_mode = (known after apply)
- self_link = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
```
Terraform will indicate what infrastructure changes it plans to make, and prompt for your approval before it makes those changes. This output shows the execution plan, describing which actions Terraform will take in order to create infrastructure to match the configuration. The output format is similar to the diff format generated by tools such as Git.
Inspect the current state using terraform show.
```
$ terraform show
googlecomputenetwork.vpc_network:
resource "googlecomputenetwork" "vpcnetwork" {
autocreatesubnetworks = true
deletedefaultroutesoncreate = false
description = null
enableulainternalipv6 = false
gatewayipv4 = null
id = "projects/test-project/global/networks/terraform-network"
internalipv6range = null
mtu = 0
name = "terraform-network"
networkfirewallpolicyenforcementorder = "AFTERCLASSICFIREWALL"
numericid = "1234567890123456789"
project = "test-project"
routingmode = "REGIONAL"
selflink = "https://www.googleapis.com/compute/v1/projects/test-project/global/networks/terraform-network"
```
In production, we recommend storing your state remotely with HCP Terraform or Terraform Enterprise. Terraform also supports several other remote backends you can use to store and manage your state.
Best Practices and Opinionated Modules
Opinionated modules exist to create Google Cloud Platform projects following best practices. This module allows you to create opinionated Google Cloud Platform projects. It creates projects and configures aspects like Shared VPC connectivity, IAM access, Service Accounts, and API enablement to follow best practices.
To include G Suite integration for creating groups and adding Service Accounts into groups, use the gsuite_enabled module.
This module is meant for use with Terraform 1.3+ and tested using Terraform 1.10+. If you find incompatibilities using Terraform >= 1.3, please open an issue.
Using an opinionated project factory reduces manual steps, enforces naming conventions, ensures billing linkage, and centralizes service account creation. The factory approach also separates the host project that holds shared resources such as state buckets and KMS keys from individual workload projects.
| Capability | Factory Module Feature |
|---|---|
| Shared VPC | Configures projects as service projects on a host network |
| IAM | Sets up project-level IAM bindings and service accounts |
| Service Accounts | Creates dedicated service accounts replacing defaults |
| API Enablement | Enables required Google APIs at project creation time |
| G Suite Integration | Optional groups integration via gsuite_enabled module |
Conclusion
Provisioning GCP projects with Terraform moves project creation from console clicks to codified, repeatable processes. The core google_project resource handles identity, billing association and folder placement, while supporting resources handle networking, encryption and logging. Service account permissions must be scoped precisely to projectCreator, billing.user and folderAdmin roles to avoid overprivilege. Random suffixes ensure globally unique project IDs and labels provide operational metadata.
State management is critical once projects exist. Remote backends protect state files, import blocks or terraform import bring existing resources under Terraform control, and API enablement remains a deliberate step after project creation. Opinionated modules bundle Shared VPC, IAM, service accounts and API enablement into reusable patterns, tested against Terraform 1.3+ and up to Terraform 1.10+. Combining granular resource definitions with factory modules yields consistent, auditable and secure GCP project lifecycles from creation through decommission.
Sources
- github.com/cdcme/terraform-google-project
- developer.hashicorp.com/terraform/tutorials/gcp-get-started/google-cloud-platform-build
- oneuptime.com/blog/post/2026-02-23-how-to-handle-gcp-project-creation-with-terraform/view
- docs.cloud.google.com/docs/terraform/understanding-apis-and-terraform
- github.com/terraform-google-modules/terraform-google-project-factory