Terraform

The Essence of terraform apply: Designing Safe Change Application and Approval Flows

2026-04-19
NicheeLab Editorial Team

terraform apply is the command that ultimately applies changes to your infrastructure. The exam frequently asks about its relationship with plan, how to insert approval steps, and safety mechanisms like locking and parallelism.

This article walks through how to design change review, approval, and application — for both standalone CLI and Terraform Cloud/Enterprise — broken down into concrete procedures and decision criteria.

How terraform apply Works and the Points the Exam Tests

terraform apply runs both planning and application. In interactive mode it shows the diff plan and continues once you answer Yes at the approval prompt. With -auto-approve it applies without approval, but this is not recommended in production.

To insert approval safely, generate a binary plan file with terraform plan -out, review it manually, and then apply it via terraform apply planfile. The plan file assumes the same working directory and dependencies (provider versions, variables, etc.), so it is not suited for long-distance or long-term portability.

State is refreshed by default (suppress with -refresh=false). Locking is enabled on supported backends and controlled by -lock and -lock-timeout. Parallelism is set with -parallelism.

  • plan exit codes: 0 (no changes), 2 (changes present), 1 (error). apply returns 0 on success and non-zero on failure.
  • terraform apply -refresh-only and plan -refresh-only let you run drift detection and state-only updates.
  • -input=false runs non-interactively (for CI). Inject variables via -var, -var-file, environment variables, or .tfvars files.
  • terraform destroy is the dedicated destruction command. apply -destroy is equivalent, but destroy makes intent clearer.

Building a Manual Approval Flow with the CLI (Saved-Plan-Driven)

The most robust minimal-approval flow treats the saved plan as an artifact with a manual approval gate. Review is done against plan's text output, while apply uses the saved plan itself to guarantee reproducibility.

The key points: separate the review artifact (human-readable plan text) from the apply artifact (the machine-readable plan file), enable state locking during apply, and validate in CI that the working tree and provider versions match.

  • Generate a saved plan: terraform plan -out=plan.tfplan -var-file=... -lock-timeout=... -input=false
  • Review: paste the plan text output into the PR (use terraform show -no-color plan.tfplan to format it)
  • Apply after approval: terraform apply plan.tfplan (combined with -lock and -lock-timeout)
  • Guardrails: apply only from the main branch, release via tagging, and never use -auto-approve

Approval flow using a CLI saved plan

Developercommitterraform plan-out tfplanPlan Review(human)terraform apply tfplanlockCloud ResourcesOn reject, return to a fix-up commit

Designing the Approval Flow in Terraform Cloud/Enterprise

Terraform Cloud/Enterprise (TFC/E) provides remote execution along with organization-wide approval and policy controls. With VCS integration, opening a pull request automatically generates a speculative plan (a dry-run with no apply), and merging to main triggers the plan in the production workspace. If you configure the workspace to require manual approval for Apply, nothing applies until a human clicks Approve.

Sentinel policies and Run Tasks let you implement guardrails. Hard-mandatory rules block execution on violation; soft-mandatory rules warn and allow manual continuation. You can also leverage cost estimation, audit logs, and protection of sensitive values.

  • Speculative plan: safe diff inspection on the PR (no apply)
  • Manual approval: require an approval step before Apply at the workspace level
  • Policy: enforce organization standards via Sentinel or OPA-equivalent Run Tasks
  • State and locking: managed centrally by TFC/E to prevent conflicts
ItemCLI StandaloneTerraform Cloud/EnterpriseGitOps CI/CD
Approval pointThe apply runner decides after manual reviewWorkspace manual approval plus policy evaluationPR review plus per-environment job approval
ArtifactSaved plan (tfplan) and plan outputPlan results and policy reports inside the RunCI logs and an optional saved plan
State storage / lockingBackends like S3 + DynamoDBManaged within TFC/E with automatic lockingDepends on the backend (shared foundation recommended)
Policy / guardrailsLint and validate via scriptsSentinel/Run Tasks/Cost EstimationPolicy steps (OPA, tfsec, etc.)
AuditabilityDepends on CI logs and manual record-keepingAudit logs at the organization and workspace levelCI audit logs and signed releases
Sensitive dataDepends on how env and var-files are handledProtected attributes on Variables and redacted outputDepends on CI secret management

Conflicts and Safety: Knack of Locking, Parallelism, and Re-runs

State locking prevents destructive conflicts from concurrent runs. With the S3 backend, you pair it with a DynamoDB table to implement locking; Consul and TFC/E provide locking natively. apply uses -lock=true by default, and you can extend wait time on contention with -lock-timeout.

Parallelism is controlled by -parallelism. The default sits around 10 (varies by environment). Raise it when creating many resources with few dependencies, and lower it for APIs with strict rate limits.

When re-running, assume idempotency but account for provider diff evaluation and external changes (drift). When drift is suspected, the safer move is to first reconcile state with reality using plan -refresh-only or apply -refresh-only.

  • Locking with the S3 backend: enable it by configuring a hash key on a DynamoDB table
  • Tune contention waits with options like -lock-timeout=5m
  • -parallelism=1 forces sequential execution (mitigates rate limits)
  • Pin provider versions and detect drift in CI with terraform init -lockfile=readonly

Common Pitfalls and Troubleshooting

Saved-plan apply failure: apply fails when provider versions, configuration, or variables change after the plan was generated. Limit usage to short-lived handoffs within the same working directory and the same dependencies.

Misuse of -auto-approve: to prevent accidental immediate production rollout in CI, isolate jobs per environment and always require manual approval on the apply step.

Overuse of -target: localized apply tends to break dependency-graph consistency. Avoid it outside of emergency escape hatches; fix the root cause and apply the full plan instead.

  • In CI, fail fast in the order terraform fmt -check, terraform validate, terraform plan
  • Mitigate API throttling errors by lowering -parallelism and adding retry policies
  • Be cautious when state locks need to be released. Force-unlock is a last resort

Production Template (Example of a Safe Apply Script)

An example script with the minimum set of safety guards. It generates and stores a saved plan, emits reviewable text, and after approval applies the same plan. It assumes a backend like S3 + DynamoDB.

Split variable files and backend configuration per environment, and identify the apply target explicitly via branch or tag.

  • Specify -input=false explicitly for non-interactive execution
  • Exit immediately on failure and propagate the exit code back to CI
  • Always consume the saved plan during apply, and forbid direct apply without a plan

Saved-plan-driven approve-and-apply template (bash)

# 初期化(ロックファイルを尊重)
terraform init -lockfile=readonly || exit 1

# 変数と並列度、ロック待機を調整
ENV=prod
TFVARS=env/${ENV}.tfvars
PLAN_OUT=.artifacts/${ENV}.tfplan
mkdir -p .artifacts

# 計画を生成(保存プラン)
terraform plan \
  -var-file="${TFVARS}" \
  -out="${PLAN_OUT}" \
  -lock=true -lock-timeout=5m \
  -parallelism=5 \
  -input=false || exit 1

# レビュー用にテキスト化(PRに添付)
terraform show -no-color "${PLAN_OUT}" > .artifacts/${ENV}.plan.txt || exit 1

# --- ここで人手承認を実施(CIのManualジョブなど) ---

# 承認後に同一プランを適用
terraform apply -input=false -lock=true -lock-timeout=5m "${PLAN_OUT}" || exit 1

echo "Apply finished for ${ENV}"

Check Your Understanding

Associate

問題 1

Your organization requires manual approval before production apply. Using only the CLI, which option is the safest practice?

  1. Create a saved plan with terraform plan -out, review the plan output, then pass the same saved plan to terraform apply
  2. Use terraform apply -auto-approve and only roll back on failure
  3. Save only the text output of terraform plan and re-run terraform apply in interactive mode at apply time
  4. Delete the environment with terraform destroy and recreate it to eliminate the diff

正解: A

By generating a saved plan, reviewing it, and applying that same plan, you prevent any drift between what was planned and what gets applied. -auto-approve should be avoided in production, and if you save only the plan text and rerun apply, the plan is recomputed and may diverge from what was reviewed. destroy contradicts the requirement.

Frequently Asked Questions

How long can a saved plan (tfplan) be reused?

It is meant for short-term handoff under the assumption that the working directory and dependencies (provider versions, modules, variable inputs) all match. Apply can fail once configuration or binaries change, so avoid long-term storage or reuse across environments.

When is it OK to use -auto-approve?

It is useful for testing environments or temporary sandboxes, but production runs should always include human approval and policy checks. In Terraform Cloud/Enterprise, configure manual approval on the workspace; for CLI workflows, use a saved plan plus a manual job instead.

Who can approve runs in Terraform Cloud?

Users granted workspace access (for example, teams with Write/Apply permission) can run and approve. The best practice is to separate teams and roles at the organization level, splitting Plan permission from Apply permission.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Terraform

HCL Syntax: Terraform's Configuration Language (2026)

HCL2 fundamentals for Terraform — blocks, attributes, expres...

Terraform

Terraform Authoring & Operations Pro: Complete Guide (2026)

Tactics for the Terraform Pro exam — module authoring, works...

Terraform

Terraform Providers: Plugin Management Fundamentals (2026)

Provider mechanics — required_providers, versions, mirrors, ...

Terraform

Terraform Resource Blocks: Declarative Infra Units (2026)

Resource block fundamentals — addresses, references, common ...

Terraform

Terraform Data Sources: Read-Only External Data (2026)

Data source basics — declaration, refresh behavior, dependen...

Browse all Terraform articles (102)
© 2026 NicheeLab All rights reserved.