Skip to main content

Terraform Workflow & Commands

Exam guide§2.4

With Terraform installed and authenticated, this page is how you actually operate it: the five-phase workflow, then the five commands that drive it - init, plan, apply, fmt, and destroy. The configuration language itself - resources, variables, outputs, modules - comes next.

The configuration workflow

The full IaC lifecycle is five phases. Scope is human planning before Terraform - you decide what resources a project needs and how they connect (e.g. a web-server pool plus a database tier). The remaining phases - Author, Initialize, Plan, Apply - are the Terraform workflow proper, the ones backed by terraform commands. Between Plan and Apply sits an optional validate phase that runs pre-deployment checks against organization policies.

1ScopeConfirm theresources requiredfor a project.before Terraform2AuthorAuthor theconfiguration filesbased on the scope.3InitializeDownload providerplugins, initializethe directory.4PlanView execution plan:resources created,modified, destroyed.OptionalValidateRuns pre-deploymentchecks againstorganization policies.gcloud beta terraform vet5ApplyCreate the actualinfrastructureresources.Terraform Workflow
IaC configuration workflow: Scope is pre-Terraform planning; Author → Apply is the Terraform workflow, with an optional Validate phase between Plan and Apply
GotchaScope isn't a Terraform command

Only phases 2-5 map to terraform commands (init → Initialize, plan → Plan, apply → Apply; Author is you writing .tf files). Scope is planning you do first, with no command. If a question lists the "Terraform workflow" steps, it's Author → Initialize → Plan → Apply, not Scope.

Running the workflow

With Terraform installed and authenticated, the hands-on loop is four commands - init, plan, apply, destroy - which implement the Author → Initialize → Plan → Apply workflow. On Cloud Shell, gcloud credentials are already in place, so once Terraform is installed you run the loop setup-free; verify the install first with terraform version.

CommandsRun the workflow
terraform version # confirm the install
terraform init # download the google provider plug-ins
terraform plan # preview the execution plan (no changes made)
terraform apply # create resources - prompts for 'yes'
terraform destroy # tear the resources down - also prompts for 'yes'

Copy the provider from the Registry

Author .tf files (e.g. main.tf) in a project folder such as infra/. Rather than memorize syntax, copy the provider block from the Terraform Registry: open the Google Cloud provider, click Use Provider, and copy the snippet. The source shortens to hashicorp/google. Then edit the block to set your project ID before running init.

terraform init - Initialize phase

terraform init is the first command to run after authoring a new configuration or checking out an existing one from version control. It downloads and installs the provider plugin (here, Google) so the rest of the workflow has something to talk to.

Terraform uses a plugin-based architecture: each provider is its own encapsulated binary, distributed separately from Terraform itself, so it can support the many infrastructure and service providers available. The provider block's source attribute tells init where to download the plugin from.

NumbersWhat `terraform init` does
  1. Reads the provider block's source and downloads + installs that provider binary (e.g. hashicorp/google).
  2. Creates a hidden .terraform/ directory in the current working dir, plus various bookkeeping files.
  3. Prints "Initializing provider plugins...", finds the latest plugin, and reports the installed version (e.g. v4.21).
Terminal
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/google...
- Installing hashicorp/google v4.21.0...
- Installed hashicorp/google v4.21.0 (signed by HashiCorp)
Terraform has been successfully initialized!
terraform init downloads and installs the Google provider plugin, then reports success

terraform plan - Plan phase

terraform plan creates an execution plan detailing every resource that will be created, modified, or destroyed on the next apply. It does not change any infrastructure - it's a preview.

NumbersWhat `terraform plan` does
  1. Reads the current state of existing remote objects so Terraform state is up to date.
  2. Compares the current configuration to the prior state and notes any differences.
  3. Builds a plan that modifies only what is necessary to reach your desired state.
Terminal
$ terraform plan
Terraform will perform the following actions:
# google_storage_bucket.example-bucket will be created
+ resource "google_storage_bucket" "example-bucket" {
+ force_destroy = false
+ id = (known after apply)
+ location = "US"
+ name = "student0313ab04569a94"
+ storage_class = "STANDARD"
+ uniform_bucket_level_access = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
terraform plan previews the execution plan: a + marks each resource that will be created
Gotcha`plan` changes nothing - use it as a safety check

terraform plan never creates or changes infrastructure; it only previews. Run it before committing a change to version control to confirm it behaves as expected. Use -out=FILE to save the generated plan to disk, then pass that file to terraform apply to execute exactly that plan.

terraform apply - Apply phase

terraform apply executes the actions from the plan: it creates the resources and establishes their dependencies. As with plan, it first shows the execution plan and waits for your approval before making any changes - if anything looks incorrect or unsafe, abort here and nothing is touched. The symbols next to each resource say what action Terraform will take:

+CreateTerraform will create this resource.-/+Destroy and recreateReplaced, not updated in-place.~Update in-placeAttribute changed without replacing the resource.-DestroyThe resource will be destroyed.
terraform apply / plan symbols: + create, -/+ destroy and recreate, ~ update in-place, - destroy
Terminal
$ terraform apply
Terraform will perform the following actions:
# google_storage_bucket.example-bucket will be created
+ resource "google_storage_bucket" "example-bucket" {
+ force_destroy = false
+ id = (known after apply)
+ location = "US"
+ name = "student0313ab04569a94"
}
Apply changes: yes
google_storage_bucket.example-bucket: Creating...
google_storage_bucket.example-bucket: Creation complete after 1s [id=student0313ab04569a94]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
terraform apply shows the plan, waits for approval (yes), then creates the resource
GotchaTerraform destroys and creates in dependency order

Terraform works out the order operations must happen in. Google Cloud won't let a VPC network be deleted while it still has resources, so Terraform waits until the instance is destroyed before destroying the network. If apply fails, read the error message and troubleshoot before re-running.

terraform fmt - consistent formatting

terraform fmt auto-formats your modules and code to match canonical conventions, so you don't have to hand-tune configuration to meet the standard.

NumbersFormatting best practices
  1. Separate meta arguments from other arguments - place them first or last, set off by a blank line.
  2. Indent arguments two spaces from the block definition.
  3. When two or more arguments share a block, align the values at the = sign.
  4. When a block has a nested block, place it after all the arguments.
  5. When code has multiple blocks, separate them with a blank line for readability.

Running terraform fmt rewrites the file so those rules hold - meta arguments move together, values align at the =, nested blocks drop below the arguments, and blocks gain separating blank lines:

Before terraform fmt
resource "google_compute_instance" "my-instance" {
boot_disk { #nested arguments above
initialize_params {
image="debian-cloud/debian-9"
}
}
count = 2 #meta-argument in between
name = "test"
machine_type="e2-micro" #unaligned equal signs
..
After terraform fmt
resource "google_compute_instance" "my-instance" {
count = 2 #meta-argument first
name = "test"
machine_type = "e2-micro" #align equal signs
#line space before a nested block
 
boot_disk { #nested arguments below
initialize_params {
image = "debian-cloud/debian-9"
}
}
}

terraform destroy - tear down resources

terraform destroy behaves like apply but as if all resources had been removed from the configuration - it tears them down. It's handy for ephemeral development infrastructure: spin up a dev/test/staging environment, then destroy it once you're done. You can also destroy specific resources by passing a target in the command.

Terminal
$ terraform destroy
google_storage_bucket.example-bucket: Refreshing state... [id=student0313ab04569a94]
Terraform will perform the following actions:
# google_storage_bucket.example-bucket will be destroyed
- resource "google_storage_bucket" "example-bucket" {
- force_destroy = false -> null
- id = "student0313ab04569a94" -> null
- location = "US" -> null
- name = "student0313ab04569a94" -> null
}
Plan: 0 to add, 0 to change, 1 to destroy.
google_storage_bucket.example-bucket: Destroying... [id=student0313ab04569a94]
google_storage_bucket.example-bucket: Destruction complete after 0s
Destroy complete! Resources: 1 destroyed.
terraform destroy tears the resource down: a - marks each resource that will be destroyed
Gotcha`destroy` is irreversible - data goes with the resource

Destroying infrastructure is a rare event in production. Use terraform destroy carefully: it destroys any resource and the data associated with it. If a Cloud Storage bucket holds data, that data cannot be recovered once the bucket is destroyed.