Terraform CLI & Core Workflow
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
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
| Command | Purpose | Changes Infra? |
|---|---|---|
terraform init | Initialize directory, download providers/modules, configure backend | No |
terraform validate | Check config syntax and type consistency (no API calls) | No |
terraform fmt | Auto-format .tf files to canonical HCL style | No |
terraform plan | Preview changes — show what will be created/updated/destroyed | No |
terraform apply | Execute the plan and make changes to real infrastructure | Yes |
terraform destroy | Destroy all resources managed by the config | Yes |
terraform show | Display current state or human-readable plan file | No |
terraform output | Print values of output variables | No |
terraform refresh | Sync state with real-world resources (deprecated; use -refresh-only) | No |
terraform import | Bring existing real resource under Terraform management | No (state only) |
terraform state | Advanced state manipulation subcommands | No (state only) |
terraform graph | Generate resource dependency graph in DOT format | No |
terraform console | Interactive HCL expression evaluator | No |
terraform taint | Mark resource for forced recreation (deprecated; use -replace) | No (state only) |
terraform untaint | Remove taint from a resource (deprecated) | No (state only) |
terraform workspace | Manage named workspaces (separate state instances) | No |
terraform login | Authenticate with Terraform Cloud | No |
terraform version | Print Terraform and provider versions | No |
terraform providers | Show providers required by the config | No |
terraform force-unlock | Release a stuck state lock manually | No (state only) |
3. terraform init — Deep Dive
terraform init must be run before any other command in a new or cloned working directory.
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 -reconfigureWhat terraform init does:
- Downloads provider plugins into
.terraform/providers/ - Downloads modules into
.terraform/modules/ - Initializes the backend (where state is stored)
- Creates or updates
.terraform.lock.hcl(pins provider versions) - Safe to run multiple times — fully idempotent
After init, these files/dirs are created:
| Path | Contents |
|---|---|
.terraform/ | Downloaded providers and modules (do NOT commit to Git) |
.terraform.lock.hcl | Provider version lock file (DO commit to Git) |
.terraform/terraform.tfstate | Backend 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:
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 -upgradeor when constraints change - Contains cryptographic hashes to prevent supply-chain attacks
- If missing,
terraform initcreates 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.
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-onlyPlan 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" {
}
| Symbol | Meaning |
|---|---|
+ | 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)
1terraform plan -detailed-exitcode
2# Exit 0 = Success, no changes
3# Exit 1 = Error
4# Exit 2 = Success, changes are present6. terraform apply — Deep Dive
terraform apply executes the plan — creating, updating, or destroying resources in the target platform.
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=5The saved plan pattern — safest for production:
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.tfplanThis 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:
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 -destroyImportant: 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:
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 -diffWhat 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
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
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-mirror11. Workflow Patterns
Local Development Workflow
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 interactivelyCI/CD Pipeline Workflow
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 planEmergency Targeted Apply (use sparingly)
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-approve12. Quick Reference
| Command | Key Flag | What It Does |
|---|---|---|
terraform init | -upgrade | Re-download providers at latest allowed version |
terraform init | -migrate-state | Move state to a new backend |
terraform plan | -out=file | Save plan for guaranteed apply |
terraform plan | -destroy | Preview what destroy would remove |
terraform plan | -refresh-only | Detect drift without applying config changes |
terraform plan | -detailed-exitcode | Exit 2 = changes present (for CI) |
terraform apply | -auto-approve | Skip confirmation prompt (CI/CD) |
terraform apply | plan.tffile | Apply exact saved plan |
terraform apply | -replace=addr | Force destroy and recreate one resource |
terraform apply | -target=addr | Only touch specific resource |
terraform fmt | -check | Fail if files are not formatted (CI gate) |
terraform fmt | -recursive | Format all subdirectories |
terraform destroy | -auto-approve | Destroy 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.hcl | Commit to Git; pins provider versions and hashes |
Practice Questions17
Q1. A team member pushes a new Terraform configuration. What is the correct order of the standard Terraform workflow?
Select one answer before revealing.
Q2. What does `terraform plan` do?
Select one answer before revealing.
Q3. In `terraform plan` output, what does the symbol `-/+` next to a resource indicate?
Select one answer before revealing.
Q4. Which Terraform command automatically formats .tf files to the canonical HCL style?
Select one answer before revealing.
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.
Q6. What does `terraform validate` check? (Select all that apply — more than one answer may be correct.)
Select one answer before revealing.
Q7. What is the purpose of the `.terraform.lock.hcl` file?
Select one answer before revealing.
Q8. You want to destroy only a specific resource without destroying the entire infrastructure. Which command should you use?
Select one answer before revealing.
Q9. What is the purpose of the `-target` flag in `terraform plan` and `terraform apply`?
Select one answer before revealing.
Q10. What does `terraform graph` produce?
Select one answer before revealing.
Q11. What is Terraform's `terraform console` command used for?
Select one answer before revealing.
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.
Q13. What happens when you run `terraform destroy`?
Select one answer before revealing.
Q14. What does `terraform taint` do, and why is it deprecated in modern Terraform?
Select one answer before revealing.
Q15. What is the difference between `terraform show` and `terraform state show`?
Select one answer before revealing.
Q16. What does `terraform apply -refresh-only` do?
Select one answer before revealing.
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.