Best practices for root modules Stay organized with collections Save and categorize content based on your preferences.
This document provides guidelines and recommendations to considerwhen using root modules.
Root configurations or root modules are the working directories from which yourun the Terraform CLI. Make sure that root configurations adhere to thefollowing standards (and to the previous Terraform guidelines where applicable).Explicit recommendations for root modules supersede the general guidelines.
This guide is not an introduction to Terraform. For an introduction to usingTerraform with Google Cloud, seeGet started withTerraform.
Minimize the number of resources in each root module
It is important to keep a single root configuration from growing too large, withtoo many resources stored in the same directory and state.All resources in aparticular root configuration are refreshed every time Terraform is run. Thiscan cause slow execution if too many resources are included in a single state. Ageneral rule: Don't include more than 100 resources (and ideally only a fewdozen) in a single state.
Use separate directories for each application
To manage applications and projects independently of each other, put resourcesfor each application and project in their own Terraform directories. A servicemight represent a particular application or a common service such as sharednetworking. Nest all Terraform code for a particular service underonedirectory (including subdirectories).
Split applications into environment-specific subdirectories
When deploying services in Google Cloud, split the Terraformconfiguration for the service into two top-level directories: amodulesdirectory that contains the actual configuration for the service, and anenvironments directory that contains the root configurations for eachenvironment.
--SERVICE-DIRECTORY/--OWNERS--modules/--<service-name>/--main.tf--variables.tf--outputs.tf--provider.tf--README--...other…--environments/--dev/--backend.tf--main.tf--qa/--backend.tf--main.tf--prod/--backend.tf--main.tfUse environment directories
To share code across environments, reference modules. Typically, this might be aservice module that includes the base shared Terraform configuration for theservice. In service modules, hard-code common inputs and only requireenvironment-specific inputs as variables.
Each environment directory must contain the following files:
- A
backend.tffile, declaring the Terraformbackend state location (typically,Cloud Storage) - A
main.tffile that instantiates the service module
Each environment directory (dev,qa,prod) corresponds to a defaultTerraform workspace and deploys a version of the service to that environment. These workspacesisolate environment-specific resources into their own contexts.Use only thedefault workspace.
Having multipleCLI workspaces within an environment isn't recommended for the following reasons:
- It can be difficult to inspect the configuration in each workspace.
- Having a single shared backend for multiple workspaces isn't recommendedbecause the shared backend becomes a single point of failure if it is used forenvironment separation.
- While code reuse is possible, code becomes harder to read having to switchbased on the current workspace variable (for example,
terraform.workspace == "foo" ? this : that).
For more information, see the following:
Expose outputs through remote state
Make sure you're exposing useful outputs of module instances from a root module.
For example, the following code snippet passes through the project ID outputfrom the project factory module instance as an output of the root module.
# Project root moduleterraform{backend"gcs"{bucket="BUCKET"}}module"project"{source="terraform-google-modules/project-factory/google"...}output"project_id"{value=module.project.project_iddescription="The ID of the created project"}Other Terraform environments and applications can reference root module-leveloutputs only.
By usingremote state,you can reference root module outputs. To allow use by other dependent apps forconfiguration, make sure you're exporting information that's related to aservice's endpoints, to remote state.
# Networks root moduledata"terraform_remote_state""network_project"{backend="gcs"config={bucket="BUCKET"}}module"vpc"{source="terraform-google-modules/network/google"version="~> 9.0"project_id=data.terraform_remote_state.network_project.outputs.project_idnetwork_name="vpc-1"...}Sometimes, such as when invoking a shared service module from environmentdirectories, it is appropriate to re-export the entire child module, as follows:
output"service"{value=module.servicedescription="The service module outputs"}Pin to minor provider versions
In root modules, declare each provider and pin to aminor version. Thisallows automatic upgrade to new patch releases while still keeping a solidtarget. For consistency, name the versions fileversions.tf.
terraform{required_providers{google={source="hashicorp/google"version="~> 4.0.0"}}}Store variables in atfvars file
For root modules, provide variables by using a.tfvars variables file. Forconsistency, name variable filesterraform.tfvars.
Don't specify variables by using alternativevar-files orvar='key=val' command-line options. Command-line options are ephemeral andeasy to forget. Using a default variables file is more predictable.
Check in.terraform.lock.hcl file
For root modules, the.terraform.lock.hcldependency lock file should be checked into source control. This allows for tracking andreviewing changes in provider selections for a given configuration.
What's next
- Learn aboutgeneral style and structure best practices for Terraform on Google Cloud.
- Learn aboutbest practices when using reusable modules.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-12-15 UTC.