| Tested on | Ubuntu 26.04 LTS (Resolute Raccoon) |
|---|---|
| Package | terraform 1.15.8-1 |
| Applies to | Any host with Terraform installed |
| Lab environment | Ubuntu VM with Terraform — Terraform lab environment on Ubuntu |
| Privilege | Normal user |
| Man page | Terraform CLI commands |
| Scope | Quick reference for Terraform CLI commands, configuration files, HCL block syntax, variables, expressions, meta-arguments, state and import, modules, providers, workspaces, and debugging. Not a full tutorial, function catalog, or cloud-provider guide. |
| Related guides | Terraform Associate certification course terraform init terraform plan terraform apply Terraform variables |
Keep this page open beside your terminal when you need a command or HCL pattern fast. Each entry gives quick-reference syntax, a one-line purpose, and a link to the full lesson when you need depth. Examples use terraform_data and hashicorp/local so nothing here requires cloud credentials.
Terraform CLI Commands Cheat Sheet
| Command | Purpose |
|---|---|
terraform version |
Show Terraform CLI version |
terraform init |
Initialize working directory — backend, providers, modules |
terraform fmt |
Format .tf files to canonical style |
terraform validate |
Check configuration syntax and internal consistency |
terraform plan |
Preview proposed create, update, replace, and destroy actions |
terraform apply |
Execute planned infrastructure changes |
terraform destroy |
Destroy all resources managed by this configuration |
terraform show |
Display current state or a saved plan file |
terraform output |
Print root-module output values |
Common flag variations:
terraform init
terraform init -upgrade
terraform init -reconfigure
terraform fmt
terraform fmt -recursive
terraform fmt -check
terraform validate
terraform plan
terraform plan -out=tfplan
terraform plan -var="environment=dev"
terraform plan -var-file="dev.tfvars"
terraform plan -destroy
terraform plan -refresh-only
terraform plan -detailed-exitcode
terraform show tfplan
terraform apply
terraform apply tfplan
terraform apply -auto-approve
terraform destroy
terraform destroy -auto-approve| Flag / pattern | One-line purpose |
|---|---|
init -upgrade |
Reconsider provider versions within configured constraints |
init -reconfigure |
Reinitialize backend without migrating state |
fmt -recursive |
Format child directories too |
fmt -check |
Exit non-zero when files need formatting (CI) |
plan -out=tfplan |
Save plan for later terraform apply tfplan |
plan -detailed-exitcode |
Exit 0 = no changes, 2 = changes pending, 1 = error |
plan -refresh-only |
Propose state refresh without other resource changes |
apply -auto-approve |
Skip interactive yes prompt — labs and automation only |
Deeper walkthroughs: terraform init, terraform fmt, terraform validate, terraform plan, terraform apply, terraform destroy.
Terraform Files and Directory Quick Reference
Common filenames in a module directory:
main.tf
variables.tf
outputs.tf
providers.tf
versions.tf
terraform.tfvars
*.auto.tfvarsTerraform loads every *.tf and *.tf.json file in the working directory as one module. Names like main.tf and variables.tf are conventions only — Terraform does not require them.
Generated or managed paths:
| Path | Role |
|---|---|
.terraform/ |
Provider plugins, module cache, backend metadata — recreated by terraform init |
.terraform.lock.hcl |
Provider version selections and checksums — commit for reproducible init |
terraform.tfstate |
Current state snapshot (local backend default) |
terraform.tfstate.backup |
Previous state snapshot after a write |
Do not hand-edit state files or .terraform.lock.hcl unless you know exactly why. Delete .terraform/ to force a fresh init; never delete terraform.tfstate while managed resources still exist.
Terraform HCL Syntax Quick Reference
Copyable block patterns for the constructs you reach for most often.
Terraform and provider blocks
terraform {
required_version = ">= 1.12.0"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}Resource
resource "local_file" "example" {
filename = "${path.module}/example.txt"
content = "Hello Terraform"
}Data source
data "local_file" "example" {
filename = "${path.module}/existing.txt"
}Variable
variable "environment" {
type = string
description = "Deployment environment"
default = "dev"
}Local value
locals {
name = "${var.environment}-app"
}Output
output "application_name" {
value = local.name
}Module
module "example" {
source = "./modules/example"
environment = var.environment
}Block-by-block tutorials: Terraform HCL syntax, Terraform resource, Terraform data sources, Terraform variables, Terraform output, Terraform locals, Terraform modules.
Terraform Variables and Values Cheat Sheet
Pass values at plan or apply time:
terraform plan -var="environment=dev"
terraform plan -var-file="dev.tfvars"
export TF_VAR_environment="dev"Inside a terraform.tfvars or *.auto.tfvars file:
environment = "dev"CLI variable precedence (lowest to highest) on the Terraform CLI:
| Priority | Source |
|---|---|
| 1 | default in the variable block |
| 2 | TF_VAR_<name> environment variable |
| 3 | terraform.tfvars |
| 4 | terraform.tfvars.json |
| 5 | *.auto.tfvars / *.auto.tfvars.json (later file name wins) |
| 6 | -var and -var-file on the command line, in the order provided |
HCP Terraform also supports workspace variables and variable sets with additional precedence rules — see HCP Terraform variables.
Common type constraints:
string
number
bool
list(string)
set(string)
map(string)
object({
name = string
port = number
description = optional(string)
environment = optional(string, "dev")
})
tuple([string, number])Full precedence ladder and validation: Terraform variables. Type details: Terraform data types.
Terraform Expressions, References and Functions
| Reference | Syntax |
|---|---|
| Resource attribute | local_file.example.content |
| Input variable | var.environment |
| Local value | local.name |
| Data source attribute | data.local_file.example.content |
| Module output | module.example.output_name |
Conditional:
var.environment == "prod" ? 3 : 1for expression:
[for name in var.names : upper(name)]Splat:
local_file.example[*].idCommonly used functions (not a complete catalog):
| Category | Functions |
|---|---|
| String | upper(), lower(), trimspace(), replace(), split(), join() |
| Collection | length(), keys(), values(), merge(), flatten(), distinct() |
| Type | tostring(), tonumber(), tolist(), toset(), tomap() |
| Lookup | lookup(), try(), can() |
| Encoding | jsonencode(), jsondecode(), yamlencode(), yamldecode() |
| Filesystem | file(), templatefile(), fileset() |
| Numeric | min(), max(), ceil(), floor() |
More operators and examples: Terraform expressions. Function reference depth: Terraform functions.
count, for_each and Lifecycle Quick Reference
count
resource "terraform_data" "example" {
count = 3
input = count.index
}References: terraform_data.example[0], count.index
for_each
resource "terraform_data" "example" {
for_each = toset(["web", "api"])
input = each.value
}References: each.key, each.value, terraform_data.example["web"]
| Situation | Prefer |
|---|---|
| Nearly identical numbered instances | count |
| Stable instances identified by map or set keys | for_each |
Explicit dependency:
depends_on = [terraform_data.foundation]Lifecycle meta-arguments:
lifecycle {
create_before_destroy = true
prevent_destroy = true
ignore_changes = [content]
replace_triggered_by = [terraform_data.trigger]
}ignore_changes uses attributes of the resource containing the lifecycle block; replace_triggered_by can reference other managed resources.
Dedicated lessons: Terraform count vs for_each, Terraform lifecycle, Terraform resource dependencies.
Terraform State, Import and Refactoring Commands
State subcommands inspect and edit the resource graph Terraform tracks between runs:
terraform state list
terraform state show local_file.example
terraform state mv local_file.old local_file.new
terraform state rm local_file.example
terraform state pullterraform state push replaces remote or local state with a file you supply. Use only during deliberate recovery — not as a routine command.
Import existing infrastructure:
terraform import local_file.example /path/on/diskConfiguration-driven import block:
import {
to = local_file.imported
id = "/path/on/disk"
}
resource "local_file" "imported" {
filename = "/path/on/disk"
content = "imported"
}Refactoring without destroy:
moved {
from = local_file.old
to = local_file.new
}Stop managing a resource without destroying it:
removed {
from = local_file.legacy
lifecycle {
destroy = false
}
}Refresh state without other changes:
terraform plan -refresh-only
terraform apply -refresh-onlyState depth: Terraform state explained, Terraform state commands, Terraform import, moved and removed blocks, drift and refresh-only.
Terraform Modules, Providers and Workspaces Quick Reference
Local module:
module "example" {
source = "./modules/example"
}Registry module:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
}Provider inspection:
terraform providers
terraform providers lockProvider alias:
provider "aws" {
alias = "west"
region = "us-west-2"
}
resource "aws_s3_bucket" "west" {
provider = aws.west
bucket = "example-west"
}Pass provider into a module:
module "example" {
source = "./modules/example"
providers = {
aws = aws.west
}
}CLI workspace commands (separate state instances within the same backend, when supported):
terraform workspace list
terraform workspace show
terraform workspace new dev
terraform workspace select dev
terraform workspace delete devCLI workspaces are not the same as HCP Terraform workspaces — the name collides, but HCP workspaces are remote state containers with run history and settings.
Further reading: Terraform providers, provider aliases in modules, Terraform modules, Terraform workspaces.
Terraform Debugging and Useful Environment Variables
Turn on verbose logging when a plan or apply fails without a clear error, then re-run the command that misbehaved:
export TF_LOG=DEBUG
export TF_LOG_PATH=terraform.log
terraform validate
terraform providers
terraform state list
terraform showLog levels (most to least verbose): TRACE, DEBUG, INFO, WARN, ERROR
| Variable | Purpose |
|---|---|
TF_LOG |
Log verbosity for Terraform operations |
TF_LOG_PATH |
Append enabled Terraform logs to a specified file; requires TF_LOG |
TF_VAR_<name> |
Set root-module input variable values |
TF_CLI_ARGS |
Extra arguments appended to every command |
TF_CLI_ARGS_plan |
Extra arguments appended only to terraform plan |
TF_DATA_DIR |
Override default .terraform metadata directory |
TF_WORKSPACE |
Select workspace without terraform workspace select |
Full debugging workflow: Terraform debug logging, Terraform troubleshooting.
Terraform Command Workflow Quick Reference
Day-to-day change cycle:
terraform fmt
terraform init
terraform validate
terraform plan
terraform applyTeardown:
terraform plan -destroy
terraform destroyMemorization flow:
Edit configuration
↓
terraform fmt
↓
terraform validate
↓
terraform plan
↓
Review changes
↓
terraform apply
↓
Verify outputs / stateTerraform — interview corner
What is the difference between terraform plan and terraform apply?
terraform plan compares configuration, state, and refreshed provider data, then prints a proposed change set without applying create, update, or destroy actions. terraform apply executes those changes and updates persistent state when operations succeed.
A strong answer is:
"Plan is the safety preview; apply is where infrastructure actually changes."
Why does Terraform need state?
State maps resource addresses in configuration (local_file.example) to real object IDs and last-known attributes. Providers identify objects by their own IDs, not by Terraform addresses, so state is how Terraform knows which API object to update or destroy on the next run.
A strong answer is:
"State is the ledger that binds configuration names to real infrastructure."
When should you use count versus for_each?
Use count when you need a fixed number of nearly identical instances indexed by integer. Use for_each when each instance is identified by a stable string key from a map or set — especially when instances may be added or removed without shifting indexes.
A strong answer is:
"count for numbered clones; for_each when the key matters and should stay stable."
Does marking a variable sensitive keep it out of state?
No. sensitive = true redacts values in many CLI outputs, but state can still store the value. Treat state files and remote backends as sensitive when they hold secrets.
A strong answer is:
"Sensitive controls display; state access still needs restriction."
How do Terraform CLI workspaces differ from HCP Terraform workspaces?
CLI workspaces are extra named state instances for one configuration on one backend. HCP Terraform workspaces are remote containers with their own state, variables, run history, and access control in a hosted organization.
A strong answer is:
"CLI workspaces provide separate state instances within one backend; HCP workspaces are separate managed infrastructure workspaces."
References
- Terraform CLI commands — official command reference
- Terraform language documentation — HCL syntax and blocks
- Terraform Associate (004) study materials — official exam resources and sample questions
- Variable definition precedence — HashiCorp precedence documentation

