Core Terraform workflow
The canonical loop
terraform init → terraform fmt / validate → terraform plan → terraform apply → eventually terraform destroy.
- init initializes the working directory: downloads providers and child modules, writes
.terraform.lock.hcl, and configures the backend. Re-run it after changing the backend block, provider requirements or module sources.-upgradepermits newer versions within constraints. - fmt rewrites files to canonical style;
fmt -checkonly reports (non-zero exit when files differ). - validate performs syntax and static type checks without contacting provider APIs.
- plan refreshes state against real infrastructure, computes a diff, and prints it.
-out=tfplansaves a binary plan. - apply executes the changes and updates state.
terraform apply tfplanexecutes exactly that saved plan and does not re-plan or prompt for a yes. - destroy is apply with every managed object removed.
Traps
plan -detailed-exitcode: 0 = no changes, 1 = error, 2 = changes present. CI gates depend on this.- Applying a saved plan will not pick up anything changed after the plan was written.
validatesuccess does not implyplansuccess - credentials, unknown values and API errors surface only at plan.initis required beforeplanin a fresh checkout, and again after adding a module.
Worked example
A pipeline runs terraform init, terraform validate, terraform plan -out=tfplan -detailed-exitcode, fails the build on exit code 1, skips apply on exit code 0, and applies tfplan only after manual approval on exit code 2.