Terraform quick-reference covering the most essential CLI commands, HCL configuration syntax, state management, and workflow patterns. Organized by task for fast lookup during infrastructure-as-code development.
Core Workflow Commands
| Command | Description |
|---|---|
| terraform init | Initialize working directory, download providers and modules |
| terraform plan | Preview changes without applying them |
| terraform plan -out=plan.tfplan | Save plan to a file for exact apply later |
| terraform apply | Apply changes interactively (prompts for confirmation) |
| terraform apply plan.tfplan | Apply a saved plan file without prompting |
| terraform apply -auto-approve | Apply changes without confirmation prompt |
| terraform destroy | Destroy all managed infrastructure |
| terraform destroy -target=aws_instance.web | Destroy a specific resource only |
Validation & Formatting
| Command | Description |
|---|---|
| terraform validate | Check configuration syntax and internal consistency |
| terraform fmt | Reformat .tf files to canonical HCL style |
| terraform fmt -check | Check formatting without modifying files (CI-friendly) |
| terraform fmt -recursive | Format files in subdirectories too |
| terraform console | Open interactive expression evaluation console |
State Management
| Command | Description |
|---|---|
| terraform state list | List all resources tracked in state |
| terraform state show <resource> | Show attributes of a resource in state |
| terraform state mv <src> <dst> | Move/rename a resource in state |
| terraform state rm <resource> | Remove a resource from state (keeps real resource) |
| terraform state pull | Download remote state as JSON to stdout |
| terraform state push <file> | Upload a local state file to the remote backend |
| terraform state replace-provider <old> <new> | Change the provider for resources in state |
| terraform refresh | Update state to match real infrastructure |
| terraform import <resource> <id> | Import existing infrastructure into state |
| terraform force-unlock <lock-id> | Release a stuck state lock |
Workspaces
| Command | Description |
|---|---|
| terraform workspace list | List all workspaces |
| terraform workspace show | Show the current workspace name |
| terraform workspace new <name> | Create and switch to a new workspace |
| terraform workspace select <name> | Switch to an existing workspace |
| terraform workspace delete <name> | Delete a workspace (must not be current) |
Inspection & Debugging
| Command | Description |
|---|---|
| terraform show | Show current state in human-readable form |
| terraform show plan.tfplan | Show a saved plan in human-readable form |
| terraform output | List all output values from the root module |
| terraform output <name> | Show a specific output value |
| terraform output -json | Output all values as JSON |
| terraform graph | dot -Tpng > graph.png | Generate a visual dependency graph |
| terraform providers | List providers required by the configuration |
| terraform version | Show Terraform and provider versions |
| TF_LOG=DEBUG terraform plan | Run with debug-level logging |
HCL Configuration Blocks
| Block | Description |
|---|---|
| terraform { } | Required providers, backend config, and version constraints |
| provider "<name>" { } | Configure a provider (e.g. aws, azurerm, google) |
| resource "<type>" "<name>" { } | Declare an infrastructure resource |
| data "<type>" "<name>" { } | Read-only data source to fetch external info |
| variable "<name>" { } | Declare an input variable with type, default, description |
| output "<name>" { } | Expose a value from the module |
| locals { } | Define local computed values for reuse within a module |
| module "<name>" { } | Call a child module with source and input variables |
Resource Meta-Arguments
| Argument | Description |
|---|---|
| count | Create multiple instances by index (count.index) |
| for_each | Create instances from a map or set (each.key, each.value) |
| depends_on | Explicit dependency on another resource or module |
| provider | Select a non-default provider configuration |
| lifecycle { prevent_destroy = true } | Prevent accidental deletion of the resource |
| lifecycle { create_before_destroy = true } | Create replacement before destroying original |
| lifecycle { ignore_changes = [tags] } | Ignore changes to specific attributes |
Common HCL Expressions
| Expression | Description |
|---|---|
| var.<name> | Reference an input variable |
| local.<name> | Reference a local value |
| module.<name>.<output> | Reference an output from a child module |
| data.<type>.<name>.<attr> | Reference a data source attribute |
| self.<attr> | Reference own attributes in provisioner blocks |
| terraform.workspace | Current workspace name |
| "${var.prefix}-app" | String interpolation |
| condition ? true_val : false_val | Conditional expression |
| [for s in var.list : upper(s)] | For expression (list) |
| {for k, v in var.map : k => upper(v)} | For expression (map) |
Built-in Functions
| Function | Description |
|---|---|
| file("path") | Read file contents as a string |
| templatefile("path", vars) | Render a template file with variables |
| jsonencode(value) / jsondecode(str) | JSON serialization and parsing |
| lookup(map, key, default) | Look up a map value with fallback |
| merge(map1, map2) | Merge two or more maps |
| concat(list1, list2) | Concatenate lists |
| length(collection) | Return the length of a list, map, or string |
| toset(list) | Convert a list to a set (deduplicate) |
| cidrsubnet(prefix, newbits, netnum) | Calculate a subnet CIDR from a base CIDR |
| try(expr, fallback) | Return first expression that doesn't error |
Frequently Asked Questions
What is the difference between terraform plan and terraform apply?
terraform plan generates an execution plan showing what changes will be made without modifying infrastructure. terraform apply executes the plan and creates, updates, or deletes real resources. Always run plan first to review changes before applying.
How do you manage multiple environments (dev, staging, prod) in Terraform?
Use workspaces (terraform workspace new dev) for lightweight separation with shared config, or use separate directories/root modules per environment for stronger isolation. Workspaces share the same configuration but maintain separate state files.
How do you import existing infrastructure into Terraform?
Write a resource block matching the existing resource, then run terraform import <resource_address> <cloud_id>. For example: terraform import aws_instance.web i-1234567890abcdef0. Terraform adds it to state; you then run plan to verify the config matches.
What is Terraform state and why is it important?
Terraform state is a JSON file mapping your configuration to real infrastructure resource IDs. It tracks metadata, dependencies, and attribute values. Without state, Terraform cannot determine what exists or what needs to change. Remote backends (S3, GCS, Terraform Cloud) are recommended for team collaboration.
How do you handle secrets in Terraform?
Never hardcode secrets in .tf files. Use input variables marked sensitive = true, environment variables (TF_VAR_name), a secrets manager data source, or encrypted backend state. Add terraform.tfvars and *.tfstate to .gitignore.