/Terraform CLI & Core Workflow
Concept
Easy

Terraform CLI & Core Workflow

9 min read·terraform-cliterraform-initterraform-planterraform-applyterraform-destroylock-fileworkflowterraform-associate

The Terraform CLI is the primary interface for all Terraform operations. The core workflow — Write, Init, Plan, Apply, Destroy — provides a safe, predictable cycle for managing infrastructure. Understanding every CLI command, its flags, plan output symbols, and the lock file is essential for the Terraform Associate exam.


1. The Core Terraform Workflow

Rendering diagram…

This cycle is idempotent — you can run plan and apply repeatedly and Terraform will only make changes that are actually needed to reach the desired state.


2. Complete CLI Command Reference

CommandPurposeChanges Infra?
terraform initInitialize directory, download providers/modules, configure backendNo
terraform validateCheck config syntax and type consistency (no API calls)No
terraform fmtAuto-format .tf files to canonical HCL styleNo
terraform planPreview changes — show what will be created/updated/destroyedNo
terraform applyExecute the plan and make changes to real infrastructureYes
terraform destroyDestroy all resources managed by the configYes
terraform showDisplay current state or human-readable plan fileNo
terraform outputPrint values of output variablesNo
terraform refreshSync state with real-world resources (deprecated; use -refresh-only)No
terraform importBring existing real resource under Terraform managementNo (state only)
terraform stateAdvanced state manipulation subcommandsNo (state only)
terraform graphGenerate resource dependency graph in DOT formatNo
terraform consoleInteractive HCL expression evaluatorNo
terraform taintMark resource for forced recreation (deprecated; use -replace)No (state only)
terraform untaintRemove taint from a resource (deprecated)No (state only)
terraform workspaceManage named workspaces (separate state instances)No
terraform loginAuthenticate with Terraform CloudNo
terraform versionPrint Terraform and provider versionsNo
terraform providersShow providers required by the configNo
terraform force-unlockRelease a stuck state lock manuallyNo (state only)

3. terraform init — Deep Dive

terraform init must be run before any other command in a new or cloned working directory.

bash
1terraform init
2
3# Re-initialize and upgrade providers to latest allowed version
4terraform init -upgrade
5
6# Initialize without downloading modules (providers only)
7terraform init -get=false
8
9# Specify a backend config file (for partial backend configuration)
10terraform init -backend-config=backend.hcl
11
12# Migrate state from one backend to another
13terraform init -migrate-state
14
15# Reconfigure backend without migrating existing state
16terraform init -reconfigure

What terraform init does:

  1. Downloads provider plugins into .terraform/providers/
  2. Downloads modules into .terraform/modules/
  3. Initializes the backend (where state is stored)
  4. Creates or updates .terraform.lock.hcl (pins provider versions)
  5. Safe to run multiple times — fully idempotent

After init, these files/dirs are created:

PathContents
.terraform/Downloaded providers and modules (do NOT commit to Git)
.terraform.lock.hclProvider version lock file (DO commit to Git)
.terraform/terraform.tfstateBackend configuration state (not your infra state)

4. .terraform.lock.hcl — The Provider Lock File

The lock file pins the exact versions and hashes of providers to ensure every team member and CI run uses identical provider binaries:

hcl
1# .terraform.lock.hcl — commit this to version control
2provider "registry.terraform.io/hashicorp/aws" {
3  version     = "5.31.0"
4  constraints = "~> 5.0"
5  hashes = [
6    "h1:abc123...",
7    "zh:def456...",
8  ]
9}
  • Commit to Git — ensures reproducible builds across all environments
  • Updated by terraform init -upgrade or when constraints change
  • Contains cryptographic hashes to prevent supply-chain attacks
  • If missing, terraform init creates it; if present, it is honored

5. terraform plan — Deep Dive

terraform plan performs a dry run — computes the diff between your desired config and the real current state without making any changes.

bash
1# Basic plan
2terraform plan
3
4# Save plan to file (required for guaranteed CI/CD deploys)
5terraform plan -out=plan.tfplan
6
7# Pass variable values
8terraform plan -var="region=us-west-2"
9terraform plan -var-file="prod.tfvars"
10
11# Plan a destroy (show what destroy would remove)
12terraform plan -destroy
13
14# Plan only specific resources (use sparingly — can cause drift)
15terraform plan -target=aws_instance.web
16terraform plan -target=module.vpc
17
18# Refresh state before planning (default true)
19terraform plan -refresh=false
20
21# Show changes in compact format
22terraform plan -compact-warnings
23
24# Detect drift only (don't apply config changes)
25terraform plan -refresh-only

Plan Output Symbols

Terraform will perform the following actions: # aws_instance.web will be created + resource "aws_instance" "web" { + ami = "ami-0c55b159cbfafe1f0" + instance_type = "t3.micro" } # aws_security_group.web will be updated in-place ~ resource "aws_security_group" "web" { ~ description = "old description" -> "new description" } # aws_instance.old will be destroyed - resource "aws_instance" "old" { - ami = "ami-abc123" -> null } # aws_instance.db must be replaced -/+ resource "aws_instance" "db" { ~ instance_type = "t2.micro" -> "t3.micro" # forces replacement } # data.aws_ami.ubuntu will be read during apply <= data "aws_ami" "ubuntu" { }
SymbolMeaning
+Resource will be created
-Resource will be destroyed
~Resource will be updated in-place (no replacement)
-/+Resource will be destroyed then re-created (replacement)
+/-Resource will be created then destroyed (create_before_destroy lifecycle)
<=Data source will be read during apply

Plan Exit Codes (important for CI/CD)

bash
1terraform plan -detailed-exitcode
2# Exit 0 = Success, no changes
3# Exit 1 = Error
4# Exit 2 = Success, changes are present

6. terraform apply — Deep Dive

terraform apply executes the plan — creating, updating, or destroying resources in the target platform.

bash
1# Interactive apply (shows plan, asks for approval)
2terraform apply
3
4# Apply without confirmation prompt (CI/CD)
5terraform apply -auto-approve
6
7# Apply a previously saved plan file exactly (no re-planning)
8terraform apply plan.tfplan
9
10# Force replace (destroy + recreate) a specific resource
11terraform apply -replace="aws_instance.web"
12
13# Apply only specific resources
14terraform apply -target=module.vpc
15
16# Pass variables
17terraform apply -var="env=prod" -var-file="prod.tfvars"
18
19# Limit concurrent operations (default 10)
20terraform apply -parallelism=5

The saved plan pattern — safest for production:

bash
1# Step 1: Plan and save
2terraform plan -out=plan.tfplan
3
4# Step 2: Review the plan (can be shared for approval)
5terraform show plan.tfplan
6
7# Step 3: Apply exactly what was reviewed — no surprises
8terraform apply plan.tfplan

This pattern ensures that what you approved is exactly what gets applied — no new drift between plan and apply.


7. terraform destroy

Destroys all resources managed by the current configuration:

bash
1# Interactive destroy (shows plan, asks for confirmation)
2terraform destroy
3
4# Destroy without confirmation (use with extreme caution)
5terraform destroy -auto-approve
6
7# Destroy only a specific resource
8terraform destroy -target=aws_instance.web
9
10# Preview what destroy would remove (same as plan -destroy)
11terraform plan -destroy

Important: terraform destroy is equivalent to terraform apply -destroy. It uses the same plan/apply mechanism — you see exactly what will be deleted before confirming.


8. terraform fmt

Formats all .tf and .tfvars files in the current directory to the canonical HCL style:

bash
1# Format current directory
2terraform fmt
3
4# Format recursively (includes subdirectories and modules)
5terraform fmt -recursive
6
7# Check if files are formatted without modifying them (useful in CI)
8terraform fmt -check
9terraform fmt -check -recursive
10
11# Show what would change without modifying files
12terraform fmt -diff

What fmt enforces:

  • Consistent indentation (2 spaces)
  • Aligned = signs in argument blocks
  • Consistent spacing around operators
  • Ordering of meta-arguments

Run terraform fmt -check in CI to reject unformatted PRs.


9. terraform show, output, graph, console

bash
1# Show human-readable current state
2terraform show
3
4# Show human-readable view of a saved plan
5terraform show plan.tfplan
6
7# Print all output values
8terraform output
9
10# Print a specific output value (machine-readable)
11terraform output -raw bucket_name
12terraform output -json
13
14# Generate dependency graph in DOT format
15terraform graph | dot -Tsvg > graph.svg
16
17# Interactive expression evaluator
18terraform console
19> aws_instance.web.public_ip
20> var.region
21> length(var.availability_zones)

10. terraform version and providers

bash
1# Show Terraform version and provider versions
2terraform version
3
4# Show required providers and their sources
5terraform providers
6
7# Show provider dependency tree
8terraform providers tree
9
10# Mirror providers to a local directory (for air-gapped environments)
11terraform providers mirror ./local-mirror

11. Workflow Patterns

Local Development Workflow

bash
1terraform init          # First time or after adding providers
2terraform fmt           # Format before committing
3terraform validate      # Catch syntax errors
4terraform plan          # Review changes
5terraform apply         # Apply interactively

CI/CD Pipeline Workflow

bash
1# PR phase
2terraform init
3terraform fmt -check -recursive   # Fail if not formatted
4terraform validate                 # Fail on syntax errors
5terraform plan -out=plan.tfplan   # Save plan artifact
6
7# Merge/deploy phase
8terraform apply plan.tfplan       # Apply exactly the reviewed plan

Emergency Targeted Apply (use sparingly)

bash
1# Only touch one resource — use to unblock deployments
2# WARNING: leaves rest of state potentially out of sync
3terraform apply -target=aws_instance.web -auto-approve

12. Quick Reference

CommandKey FlagWhat It Does
terraform init-upgradeRe-download providers at latest allowed version
terraform init-migrate-stateMove state to a new backend
terraform plan-out=fileSave plan for guaranteed apply
terraform plan-destroyPreview what destroy would remove
terraform plan-refresh-onlyDetect drift without applying config changes
terraform plan-detailed-exitcodeExit 2 = changes present (for CI)
terraform apply-auto-approveSkip confirmation prompt (CI/CD)
terraform applyplan.tffileApply exact saved plan
terraform apply-replace=addrForce destroy and recreate one resource
terraform apply-target=addrOnly touch specific resource
terraform fmt-checkFail if files are not formatted (CI gate)
terraform fmt-recursiveFormat all subdirectories
terraform destroy-auto-approveDestroy without confirmation
Plan symbol +Resource will be created
Plan symbol -Resource will be destroyed
Plan symbol ~Resource will be updated in-place
Plan symbol -/+Resource replaced (destroy then create)
.terraform.lock.hclCommit to Git; pins provider versions and hashes

Practice Questions17

easy

Q1. A team member pushes a new Terraform configuration. What is the correct order of the standard Terraform workflow?


Select one answer before revealing.

easy

Q2. What does `terraform plan` do?


Select one answer before revealing.

easy

Q3. In `terraform plan` output, what does the symbol `-/+` next to a resource indicate?


Select one answer before revealing.

easy

Q4. Which Terraform command automatically formats .tf files to the canonical HCL style?


Select one answer before revealing.

easy

Q5. You need to apply Terraform changes in a CI/CD pipeline without human interaction. Which flag should you use with `terraform apply`?


Select one answer before revealing.

easy

Q6. What does `terraform validate` check? (Select all that apply — more than one answer may be correct.)


Select one answer before revealing.

medium

Q7. What is the purpose of the `.terraform.lock.hcl` file?


Select one answer before revealing.

medium

Q8. You want to destroy only a specific resource without destroying the entire infrastructure. Which command should you use?


Select one answer before revealing.

hard

Q9. What is the purpose of the `-target` flag in `terraform plan` and `terraform apply`?


Select one answer before revealing.

medium

Q10. What does `terraform graph` produce?


Select one answer before revealing.

medium

Q11. What is Terraform's `terraform console` command used for?


Select one answer before revealing.

medium

Q12. When using `terraform apply` with a saved plan file (`terraform apply plan.tfplan`), what is the advantage over running `terraform apply` directly?


Select one answer before revealing.

easy

Q13. What happens when you run `terraform destroy`?


Select one answer before revealing.

hard

Q14. What does `terraform taint` do, and why is it deprecated in modern Terraform?


Select one answer before revealing.

medium

Q15. What is the difference between `terraform show` and `terraform state show`?


Select one answer before revealing.

hard

Q16. What does `terraform apply -refresh-only` do?


Select one answer before revealing.

medium

Q17. Scenario: A `terraform plan` shows the following output. What action is Terraform planning? ``` # aws_instance.web must be replaced -/+ resource "aws_instance" "web" { ~ id = "i-abc123" -> (known after apply) ~ private_ip = "10.0.1.5" -> (known after apply) ~ ami = "ami-old12345" -> "ami-new67890" # forces replacement instance_type = "t3.micro" } ```


Select one answer before revealing.