Terraform Associate
Deep Dive
State commands let you inspect and manipulate the state without destroying infrastructure. Import brings existing resources into the state. Workspaces allow multiple environments with the same configuration.
Contents
# List all resources in the state terraform state list # Example output: # aws_vpc.main # aws_subnet.public[0] # aws_subnet.public[1] # aws_subnet.private["us-east-1a"] # module.eks.aws_eks_cluster.this # data.aws_ami.ubuntu # Filter by prefix terraform state list module.eks # module.eks.aws_eks_cluster.this # module.eks.aws_iam_role.cluster # View the detailed attributes of a specific resource terraform state show aws_vpc.main terraform state show 'aws_subnet.private["us-east-1a"]' # quotes needed for for_each # View in JSON format (all resources) terraform show -json | jq '.values.root_module.resources[]'
💡 Quotes in for_each addresses
Addresses of resources created with for_each include the key in brackets and quotes: aws_subnet.private["us-east-1a"]. In the shell you must escape the quotes or wrap the address in single quotes.
terraform state mv — move/rename
# Rename a resource in the state # (useful when you change the local name in the code without recreating) terraform state mv aws_instance.old_name aws_instance.new_name # Move a resource into a module terraform state mv aws_vpc.main module.networking.aws_vpc.main # Move a resource from a module to the root terraform state mv module.old.aws_s3_bucket.data aws_s3_bucket.data # ⚠️ After mv, also update the .tf code # so it matches the new address
terraform state rm — remove from the state
# Remove a resource from the state WITHOUT destroying it in the cloud # Useful when you no longer want Terraform to manage it terraform state rm aws_instance.legacy # Remove all resources of a module from the state terraform state rm module.old_module # ⚠️ The resource keeps existing in the cloud # It just stops being tracked by Terraform # If you later run apply, Terraform will IGNORE that resource # (it will not destroy it because it's not in the state)
| Command | Effect on state | Effect on real infra |
|---|---|---|
| terraform state mv | Changes the resource address in tfstate | None — the real resource is untouched |
| terraform state rm | Removes the resource from tfstate | None — the real resource keeps existing |
| terraform destroy | Removes the resource from tfstate | 🔥 DESTROYS the resource in the cloud |
| terraform apply (add) | Adds the resource to tfstate | Creates the resource in the cloud |
# Download the remote state to stdout (useful for inspection or backup) terraform state pull > backup-state.json # View the remote state without saving it terraform state pull | jq '.resources[].type' | sort | uniq # Push a local state to the remote backend # ⚠️ DANGEROUS: overwrites the remote state terraform state push backup-state.json # terraform state push requires that the serial of the state being pushed # be greater than the current serial, unless you use -force (very dangerous)
⚠️ terraform state push can corrupt the state
terraform state push overwrites the remote state. Use it only in disaster recovery situations, never as a normal workflow. If the pushed state is outdated, it can cause Terraform to incorrectly recreate or destroy resources.
Import lets you bring existing resources in the cloud (created manually or with other tools) into the Terraform state so it can manage them.
Steps to import with terraform import (classic CLI)
# Step 1: Define the resource block in your .tf code
# (with the arguments the resource already has)
resource "aws_instance" "legacy" {
# You must define the resource before importing
ami = "ami-0c55b159cbfafe1f0" # get these values from the console
instance_type = "t3.micro"
}
# Step 2: Import the resource using its real ID in the cloud
terraform import aws_instance.legacy i-0123456789abcdef0
# Step 3: Run terraform plan to see the differences
terraform plan
# May show ~ changes if the resource block doesn't match exactly
# Step 4: Adjust the .tf code until terraform plan shows "No changes"import block (Terraform 1.5+ — modern form)
# Import block in the HCL code — more declarative and reusable
import {
to = aws_instance.legacy # address in Terraform
id = "i-0123456789abcdef0" # real ID in the cloud
}
resource "aws_instance" "legacy" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
# Run:
terraform plan # shows the import plan
terraform apply # performs the import
# Bonus: terraform 1.5+ can GENERATE the resource block automatically:
terraform plan -generate-config-out=generated.tf💡 How do I know the import ID?
Each resource type has its own import ID format. The provider documentation in the registry specifies the format for each resource in the "Import" section. For example: aws_instance uses the Instance ID (i-xxx), aws_s3_bucket uses the bucket name.
CLI workspaces let you maintain multiple independent states with the same configuration. Each workspace has its own tfstate.
# Workspace commands
terraform workspace list # list all workspaces
terraform workspace show # show the active workspace
terraform workspace new dev # create workspace "dev" and activate it
terraform workspace select prod # switch to the "prod" workspace
terraform workspace delete dev # delete workspace "dev" (cannot be active)
# terraform.workspace — special variable with the active workspace's name
resource "aws_instance" "web" {
instance_type = terraform.workspace == "prod" ? "t3.large" : "t3.micro"
tags = {
Environment = terraform.workspace
}
}
# State storage per workspace:
# Local backend: terraform.tfstate.d/<workspace>/terraform.tfstate
# S3 backend: <bucket>/<key>.tfstate.d/<workspace>/terraform.tfstate
# HCP backend: separate workspace in the organization| Feature | CLI Workspaces | HCP Terraform Workspaces |
|---|---|---|
| What are they? | Multiple states of the same working directory | Full execution environments with config, variables, runs, history |
| Separate state | ✅ Yes | ✅ Yes |
| Separate variables | ❌ No — they share the code's variables | ✅ Yes — each workspace has its own variables |
| Granular access | ❌ No | ✅ Yes — per-workspace permissions |
| Run history | ❌ No | ✅ Yes |
| Recommended for | Simple environments, quick tests | Production environments, team collaboration |
Did you get this topic?
Test what you just learned
An engineer runs terraform state rm aws_s3_bucket.legacy to stop managing a bucket with Terraform. What will happen to the S3 bucket in AWS after this command?
Put what you learned to the test with original Terraform Associate exam questions.
Start Terraform Associate mock examUnlimited mock exams with the Pro plan
Log in to track your progress.