Creating a single Google Cloud Platform project in the console is straightforward. Creating dozens or hundreds of projects, one per team, per environment, per microservice, with consistent billing association, API enablement, IAM, networking and budget alerts from day one, requires automation. Terraform provides a repeatable, auditable workflow for GCP project creation and ongoing management. Every GCP resource lives inside a project. Projects are the fundamental unit of organization, billing, and access control.
This article covers how Terraform handles project creation from scratch, the project factory pattern for scale, safe deletion practices, configuration structure, and operational realities when working with APIs and imports.
Why Terraform for GCP Projects
Terraform handles project creation, billing association, API enablement, and default resource setup in a single, repeatable workflow. Project creation is often the first step in any GCP infrastructure setup. Terraform makes it repeatable, auditable, and scalable.
The project factory pattern is particularly powerful for organizations that create projects frequently. Each new project comes with the right APIs enabled, the right IAM configured, the right network setup, and budget alerts from day one.
Manual console creation works for one or two projects. At scale the risks are drift, inconsistent naming, missing API enablement, and manual billing linkage errors. Code makes those decisions explicit.
Prerequisites and Permissions for Project Creation
Creating projects requires specific permissions. The service account or user running Terraform needs organization-level permissions to create projects, link billing accounts, and enable APIs. The exact roles are typically Organization Administrator or Project Creator within the target folder or organization, plus Billing Account User for billing association.
Keep your billing account ID out of version control if you consider it sensitive. Pass it as a variable or use a data source.
Prerequisites for a Terraform workspace that will provision GCP infrastructure include:
- Terraform 1.2.0+ installed locally
- The gcloud CLI installed locally
- A GCP account with an active project
- Google Compute Engine API enabled for the initial project used for Terraform execution
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.
After creating your GCP account, create or modify the following resources to enable Terraform to provision your infrastructure.
Minimal Terraform Configuration for GCP
Each Terraform configuration must be in its own working directory.
A minimal working directory for learning can be created as follows:
$ mkdir learn-terraform-gcp
$ cd learn-terraform-gcp
$ touch main.tf
Terraform loads all files ending in .tf or .tf.json in the working directory.
A basic provider and resource configuration looks like this:
hcl
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "6.8.0"
}
}
}
provider "google" {
project = "<PROJECT_ID>"
region = "us-central1"
zone = "us-central1-c"
}
resource "google_compute_network" "vpc_network" {
name = "terraform-network"
}
This is a complete configuration that Terraform can apply. In the following sections you will review each block of the configuration in more detail.
The terraform {} block contains Terraform settings, including the required providers Terraform will use to provision your infrastructure. For each provider, the source attribute defines an optional hostname, a namespace, and the provider type. Terraform installs providers from the Terraform Registry by default.
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.
As you follow these tutorials, you will use Terraform to provision, update, and destroy a simple set of infrastructure using the sample configuration provided. The sample 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.
Scalable Project Structure for Foundations
A project structure that will scale throughout a series of Terraform modules can be bootstrapped with the following commands:
```
mkdir terraform-gcp-foundation && cd terraform-gcp-foundation
Create core Terraform files
touch main.tf variables.tf outputs.tf providers.tf terraform.tfvars
Create resource-specific files
touch networking.tf storage.tf
Create backend configuration
touch backend.tf
Initialize git for version control
git init
echo ".tfvars" >> .gitignore
echo "terraform-sa-key.json" >> .gitignore
echo ".terraform/" >> .gitignore
echo ".tfstate*" >> .gitignore
```
Why this structure is useful:
- Separation of concerns: Each file has a specific purpose
- Scalability: Easy to add new resources in dedicated files
- Team collaboration: Clear organization for multiple developers
- Version control ready: Proper .gitignore for sensitive files
Terraform Configuration Files Explained
Core files map to responsibilities:
| File | Purpose |
|---|---|
| providers.tf | Provider requirements and authentication |
| variables.tf | Input variable definitions |
| terraform.tfvars | Variable values, excluded from git |
| main.tf | Root module orchestration |
| networking.tf | VPC, subnets, firewall resources |
| storage.tf | Buckets, IAM for storage |
| backend.tf | Remote state configuration |
| outputs.tf | Exposed values for downstream modules |
This separation supports a project factory pattern where project creation logic is isolated from resource logic.
Project Creation with Billing and APIs
A GCP project resource declaration can include project ID generation, organization linkage, billing association, and network auto-creation control.
A pattern for a protected critical project is:
hcl
resource "google_project" "critical_project" {
name = "Critical Production"
project_id = "critical-prod-${random_id.suffix.hex}"
org_id = var.org_id
billing_account = var.billing_account_id
auto_create_network = false
lifecycle {
prevent_destroy = true
}
}
Practical Tips
- Project IDs are globally unique and permanent. Once a project ID is used, it cannot be reused - even after the project is deleted, the ID is permanently retired. The 30-day window is for project recovery, not ID reuse. Use a naming convention that includes a random suffix to avoid collisions.
- Some APIs take time to enable. If a resource creation fails immediately after enabling the API, add a timesleep or use explicit dependson.
- Keep your billing account ID out of version control if you consider it sensitive. Pass it as a variable or use a data source.
Pass it as a variable or use a data source for sensitive identifiers.
Project Deletion and Safety Controls
Deleting a project is a big deal - all resources inside it are destroyed. Terraform supports this, but protect against accidents.
The lifecycle block with prevent_destroy = true blocks accidental destruction during terraform destroy or apply. This is recommended for production projects created via Terraform.
When you import a resource, Terraform generates a state entry for it, allowing you to manage its lifecycle using your Terraform configuration. 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 for a Compute Engine instance:
bash
terraform import google_compute_instance.my_instance projects/your-gcp-project-id/zones/us-central1-a/instances/my-vm
Run terraform plan to check that Terraform's state matches reality before applying changes.
API Enablement and Private APIs
Terraform can enable services using googleprojectservice. Not all APIs referenced in logs require action.
Addressing Concerns about Private APIs
Customers sometimes encounter references to private APIs like dataproc-control.googleapis.com for Managed Service for Apache Spark 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 and are managed by Google.
Only enable public APIs that your workloads require. Enabling unnecessary services increases attack surface.
Remote Backends and Variables
With Terraform installed, you are ready to create some infrastructure.
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.
Input and output variables, remote backends, and resource dependencies are the building blocks for more complex configurations.
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.
Project Factory Pattern at Scale
The project factory pattern is particularly powerful for organizations that create projects frequently. Each new project comes with the right APIs enabled, the right IAM configured, the right network setup, and budget alerts from day one.
Typical factory outputs include:
- Project with unique, non-reusable project_id
- Billing account linkage
- Default service accounts disabled or restricted
- Required APIs enabled via googleprojectservice
- Folder and organization placement
- IAM bindings for teams
- Default network disabled or custom network created
This guide covers creating GCP projects with Terraform from scratch, including the tricky parts like billing accounts, default networks, and the project factory pattern for managing many projects at scale.
For related topics, see our guide on handling GCP folder and organization management in Terraform.
Conclusion
Project creation is often the first step in any GCP infrastructure setup. Terraform makes it repeatable, auditable, and scalable. The project factory pattern is particularly powerful for organizations that create projects frequently - each new project comes with the right APIs enabled, the right IAM configured, the right network setup, and budget alerts from day one.
Safe operations require treating project IDs as permanent, protecting production projects with lifecycle prevent_destroy, handling API enablement delays with explicit dependencies, and keeping sensitive identifiers like billing account IDs out of version control. A disciplined file structure with separation of concerns, version control hygiene, and remote state enables team collaboration at scale.
Terraform’s ability to provision, update, destroy, and import GCP projects gives teams control over the entire lifecycle from initial organization to decommissioning, with state accuracy verified via plan and apply.