TerraformV · The Terraform WorkflowApply
terraform apply: From Plan to Reality
What you'll learn
- Describe the apply workflow and approval gates
- Explain the difference between interactive apply and saved-plan apply
- Recognise the structure of a partial apply failure
- Apply a production apply workflow
Prerequisites
Verified against Terraform CLI 1.9.x · OpenTofu 1.7.x · HCL 2.0 · bpg/proxmox provider 0.66+ · hashicorp/local provider 2.5+ · hashicorp/null provider 3.2+ · hashicorp/random provider 3.6+ · hashicorp/http provider 3.4+ · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · 2026-08-12
Apply is the moment the plan becomes reality. Every consideration that previously existed only in the configuration, the state, and the plan output now touches real infrastructure. This lesson covers what apply does, how to control it, and how to recover when it fails halfway through.
What apply does
The apply command:
- Re-runs the plan (unless a saved plan is provided).
- If the plan is empty, exits without changing anything.
- Otherwise, prompts for approval (unless
-auto-approveis set). - Walks the resource graph in dependency order.
- For each resource, sends the appropriate API call to the provider.
- Updates state after each successful operation.
- Writes the final state to the backend.
The apply is the irreversible step. The plan is a proposal. The apply is the change.
Interactive apply vs saved-plan apply
Two modes that produce different audit trails:
Interactive apply
terraform apply
Plan: 2 to add, 0 to change, 0 to destroy, 0 to replace.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
The plan is computed at apply time. The engineer sees the plan and decides whether to proceed. The audit trail is the engineers “yes” — which is logged in the apply output but not separately stored.
Pitfall: the plan is computed at the moment of apply. If the
state or configuration has changed between terraform plan and
terraform apply, the apply produces a different plan. The
engineer sees the new plan and approves it. This is fine if the
engineer notices the new plan is different from what they
expected. It is a problem if the difference is subtle.
Saved-plan apply
terraform plan -out=production.tfplan
terraform apply production.tfplan
The plan is computed once, written to a file, and applied verbatim. The apply does not re-plan; it executes the saved plan exactly. The audit trail is the saved plan file, which can be archived, reviewed, and compared to the actual diff.
A saved plan is the operational version of a code review. It says “this is what we agreed to apply; nothing else is acceptable”. A production CI/CD pipeline should use saved-plan apply.
The apply process in detail
The apply walks the resource graph in topological order. For each resource, the core asks the provider to perform the change:
Plan: 1 to add, 0 to change, 0 to destroy.
aws_security_group.alb: Creating...
aws_security_group.alb: Still creating... [10s elapsed]
aws_security_group.alb: Still creating... [20s elapsed]
aws_security_group.alb: Creation complete after 25s [id=sg-0abc123def456789]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
The state is updated after each individual resource. This is intentional: it means that if the apply fails halfway through, the state records what succeeded.
Parallelism
By default, the apply executes up to 10 independent resources in
parallel. The default is configurable with -parallelism=N:
terraform apply -parallelism=20
Increasing parallelism:
- Does not change the plan.
- Reduces wall-clock time when the graph has many independent resources.
- May exhaust provider API rate limits.
- Does not change the correctness of the apply.
Reducing parallelism:
- Slows down the apply.
- Helps when the provider is rate-limited.
- Helps when the apply is causing observable problems in the target environment.
A production default of 10 is reasonable. Tuning is a follow-up.
Refresh during apply
By default, the apply does not refresh state before applying. The plan used the state as it was when the plan ran. If the real world has changed since the plan, the apply may:
- Fail because the resource is no longer in the expected state.
- Succeed but produce a different result than the plan implied.
- Succeed and diverge from reality, leaving state stale.
The course returns to this in Part XL (Refresh Behaviour).
What happens when apply fails midway
The canonical case: 6 resources planned, 4 succeeded, 5th failed.
Plan: 6 to add, 0 to change, 0 to destroy.
aws_security_group.alb: Creating...
aws_security_group.alb: Creation complete after 25s [id=sg-0abc123def456789]
aws_lb_target_group.api: Creating...
aws_lb_target_group.api: Creation complete after 18s [id=arn:...]
aws_lb.api: Creating...
aws_lb.api: Still creating... [30s elapsed]
aws_lb.api: Still creating... [1m elapsed]
aws_lb.api: Error: error creating API Gateway Load Balancer: AccessDeniedException
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
What state looks like:
- 2 resources added successfully, in state.
- 1 resource failed, in state with partial attributes.
- 3 resources not yet started, not in state.
What does the next plan do?
Plan: 4 to add, 0 to change, 0 to destroy.
The plan reads the state. It sees the 2 added resources as current. It sees the 3 not-started resources as needing to be created. The 1 failed resource is not in state at all (because the provider did not return a successful response), so it does not appear in the next plan unless the engineer re-attempts it.
The recovery procedure is:
- Investigate the failure. What went wrong? Was it a permissions error, a quota error, a network failure, or something else?
- Fix the cause. If it was a permissions error, grant the missing permission. If it was a quota error, request a quota increase. If it was a configuration error, fix the configuration.
- Re-plan.
terraform planshould now show the 4 resources that were not yet created. - Review the plan. Compare to the expected diff.
- Apply. The apply will create the remaining resources.
Why there is no transactional rollback
A common user expectation: “if apply fails halfway, Terraform should undo the changes it made earlier”.
Terraform does not do this, and the design choice is intentional:
- Rollback is provider-specific. Some providers can roll back a creation; others cannot. A database creation is not reversible. An IAM role creation is reversible.
- Rollback is state. Rolling back means creating new resources to undo the earlier ones. The new resources may also fail.
- Rollback hides the failure. The engineers attention should be on the failure, not on a partially-completed rollback.
The courses recommendation: plan for partial apply. Work
the configuration into a sequence where any single failure is
visible and recoverable. Use prevent_destroy on resources that
should never be destroyed. Use lifecycle.precondition to
verify assumptions before applying.
Failure modes during apply
The most common failure categories:
| Failure | Symptom | Recovery |
|---|---|---|
| Permission denied | Provider returns 403 | Grant the missing permission; verify with a manual API call |
| Quota exceeded | Provider returns 429 or quota error | Request quota increase; consider smaller batches |
| Resource conflict | Provider returns a uniqueness error | Reconcile with the real-world resource; import or remove |
| Network failure | TCP or TLS error | Retry; check providers status page |
| API outage | Provider returns 5xx | Wait for provider to recover; re-plan |
| Configuration error | Terraform validates the plan, but the provider rejects the apply | Fix the configuration; re-plan |
| State mismatch | Providers view of the resource is inconsistent with state | Investigate; terraform state commands to reconcile |
The first three categories (permission, quota, conflict) are the most common in production. They are also the most controllable: the relevant IAM policy and quota should be checked before the apply.
Apply in CI/CD
A production CI/CD pipeline uses saved-plan apply:
# Save the plan in CI
terraform init -input=false
terraform validate
terraform plan -out=tfplan -input=false
# Run the plan as a "test" that captures the diff
terraform show -json tfplan > plan.json
# Wait for human approval of the PR
# ...
# After approval, apply the saved plan
terraform apply -input=false tfplan
The CI pipeline never invokes terraform apply without a saved
plan. The saved plan is the contract between the engineer and the
CI pipeline.
Some CI pipelines also automatically upload the saved plan to artifact storage, so the audit trail is preserved:
artifacts:
paths:
- tfplan
expire_in: 1 year
The course has a dedicated lab for the CI workflow in Part LXXXVII.
When to use -auto-approve
The -auto-approve flag is appropriate in three contexts:
- CI/CD pipelines that have already approved the plan via a separate gate (PR review, manual approval, policy engine).
- Emergency operations that have gone through explicit out-of-band approval and need to apply without delay.
- Disaster recovery where the saved plan is the only record of what was intended.
It is not appropriate for:
- A new engineer who has not yet learned the plan reading workflow.
- A change that “should be fine” without a separate review.
- An apply that has not been costed.
The apply output
The apply output is the operational record of what changed:
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
This is the summary. The full output lists the timing and outcome of each resource. A production apply log should be archived alongside the saved plan.
What comes next
The next lesson is terraform destroy — the most dangerous operation in Terraform, the operation that turns a configuration no longer in use into infrastructure that no longer exists.
Knowledge check · 7 questions
Q1. What is the role of terraform fmt?
Q2. What is the role of terraform validate?
Q3. What is the role of terraform init?
Q4. terraform plan modifies the real world.
Q5. Which of the following are part of the safe workflow? (Select all that apply.)
Q6. What does terraform show do?
Q7. A team runs terraform plan and sees no changes. The apply also shows no changes. The real world has drifted. What should they do?
Passing score: 75%. Answers are checked in this browser.