Terraform Workflow: Init, Plan, and Apply¶
Overview¶
Run the full local lifecycle — fmt, validate, init, plan, apply, destroy — and explain what each command does to configuration, state, and providers.
Every production change follows the same loop: format and validate, initialise the working directory, review a plan, apply deliberately, and destroy when a lab or environment should go away. Master these verbs before writing complex HCL.
This is a core tutorial in Module 3 · Terraform Basics of the REBASH Academy Terraform for Cloud & DevOps Engineers series — written for Cloud, DevOps, Platform, and SRE engineers.
Prerequisites¶
- Installing Terraform and the CLI Workflow
- Working
terraform1.x binary
Learning Objectives¶
By the end of this tutorial, you will be able to:
- State what
init,plan,apply, anddestroychange - Use
fmtandvalidatebefore planning - Read a plan summary (add / change / destroy)
- Apply and tear down a local
local_fileresource safely
Architecture¶
This topic’s control points and relationships are shown below.
Theory¶
What it is¶
The Terraform CLI workflow is a disciplined sequence of commands around one root module (a directory of .tf files):
| Command | Role |
|---|---|
terraform fmt | Rewrites HCL to canonical style |
terraform validate | Checks configuration syntax and basic consistency |
terraform init | Downloads providers/modules; configures backend |
terraform plan | Shows the proposed delta vs current state |
terraform apply | Executes a plan (or plans then applies interactively) |
terraform destroy | Plans and applies deletion of managed resources |
State (often terraform.tfstate locally) is updated on successful apply/destroy so the next plan starts from reality Terraform last knew.
Why it matters¶
Skipping plan review is how teams ship accidental destroys. Pipelines should run fmt (check mode), validate, and plan on every pull request, and apply only from an approved plan artefact or a controlled environment. Understanding each command prevents treating Terraform as a vague “deploy button”.
How it works¶
fmt— normalises indentation and argument alignment; no API calls.validate— parses HCL and checks references; needs init for provider schemas in most setups.init— readsrequired_providers, fetches plugins, initialises the backend, installs modules.plan— refreshes state (unless disabled), walks the graph, prints create/update/delete actions.apply— runs the same planning logic (unless given a saved plan file), prompts for approval, then calls providers and writes state.destroy— special apply that targets removal of all (or selected) managed objects.
Saved plans (terraform plan -out=tfplan then terraform apply tfplan) freeze the reviewed change set for CI — prefer that pattern in production pipelines.
Key concepts and comparisons¶
| Command | Touches APIs? | Updates state? |
|---|---|---|
fmt / validate | No | No |
init | Registry / module sources | No (configures backend) |
plan | Often refresh reads | No (unless you use exotic flags) |
apply / destroy | Yes | Yes on success |
Common pitfalls¶
- Running
applywithout reading the plan summary. - Re-running
initas if it were deploy — init prepares; apply changes infrastructure. - Editing state by hand instead of using supported commands.
- Forgetting that
destroyis still an apply of deletions — review it like any other plan. - Committing local
terraform.tfstatewith secrets — use remote state later; never publish state files.
Hands-on Lab¶
Create a workspace for this tutorial.
Focus: Walk the init → plan → apply loop with a saved plan file
Step 1 – Initialise and create a plan artefact¶
cat > main.tf <<'EOF'
terraform {
required_providers {
local = { source = "hashicorp/local", version = "~> 2.5" }
null = { source = "hashicorp/null", version = "~> 3.2" }
}
}
resource "null_resource" "workflow" {
triggers = { step = "plan-apply" }
}
resource "local_file" "note" {
filename = "${path.module}/workflow.txt"
content = "init-plan-apply
"
}
EOF
terraform init
terraform plan -out=tfplan
terraform show -no-color tfplan | head -n 30
Step 2 – Apply the saved plan and confirm state¶
terraform apply tfplan
cat workflow.txt
terraform state list
terraform plan -detailed-exitcode || test $? -eq 0
Final step – Cleanup note¶
terraform destroy -auto-approve
# Workspace kept for notes; remove with: rm -rf "$(pwd)" when finished
Validation¶
- Lab commands run under
~/rebash-terraform/module-03/ - You can explain each Theory section in your own words
- You used modern tooling where it applies to this topic
- You can describe one production failure mode for this topic
Code Walkthrough¶
Production practice for Terraform Workflow: Init, Plan, and Apply always combines:
- Inspect before you change (status, plan, logs, dry-run)
- Prefer reversible, documented changes (Git, IaC, drop-ins, version pins)
- Capture evidence (command output, pipeline logs) for handovers
- Prefer current tools and APIs over legacy shortcuts
- Least privilege — escalate credentials only when required
Keep runbooks short enough to follow under pressure. Automate checks; keep humans for judgement.
Security Considerations¶
- Treat credentials and tokens for terraform as privileged — never commit them
- Prefer short-lived auth (OIDC, roles, SSO) over long-lived keys
- Validate blast radius before apply/deploy/delete operations
- Restrict who can approve production changes
- Collect audit logs; limit who can read sensitive traces
Common Mistakes¶
Running apply without reading the plan summary.
Validate assumptions against the Theory section and official docs before changing production.
Re-running init as if it were deploy — init prepares; apply changes infrastructure.
Lab shortcuts (open security groups, admin roles, skip approvals) must not ship unchanged.
Changing production without a rollback path
Always know how to revert (previous artefact, prior release, state rollback, DNS failback).
Best Practices¶
- Encode Terraform Workflow: Init, Plan, and Apply changes as code and review them in pull requests
- Pin versions (images, modules, actions, provider plugins)
- Separate environments with clear promotion gates
- Alert on symptoms with runbooks attached
- Destroy lab resources; tag everything with owner and expiry where possible
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Auth / permission denied | Wrong identity, policy, or scope | Check caller identity, roles, and least-privilege policies |
| Timeout / no route | Network, DNS, security group, or endpoint | Trace path, DNS, and allow-lists before retrying |
| Drift / unexpected plan | Manual change or wrong state/workspace | Reconcile desired vs actual; avoid click-ops on managed resources |
| Pipeline/job red | Flaky step, cache, or missing secret | Read failing step logs; bisect recent workflow/config changes |
| Cost spike | Idle load balancer, NAT, oversized compute | Inventory billable resources; stop/delete labs promptly |
Summary¶
Terraform Workflow: Init, Plan, and Apply is essential for Cloud and DevOps engineers working with terraform. Practise the lab until the inspection and change path is muscle memory, then continue the track.
Interview Questions¶
- What is the purpose of each stage: init, plan, and apply?
- Why save a plan with
-outbefore applying? - What does a subsequent plan with no changes tell you?
- What can go wrong if someone applies while another engineer plans against stale state?
- How should interactive approval differ between laptops and CI?
Sample answer — question 2
A saved plan freezes the changeset reviewers approved. Applying that file avoids a newer unexpected plan. It is the usual pattern for CI apply jobs.
Sample answer — question 4
Without locking, two operators can race and corrupt state or apply conflicting changes. Remote backends with locking serialise applies and reduce this risk.