Skip to content
SRE & DevOpsDeep Dive Published Updated 9 min readViews unavailable

Terraform Targeted Plans and Resource Replacement: Recovery Without Hiding Drift

Use Terraform -target only for exceptional recovery, distinguish it from -replace, and return to a complete plan before normal operations resume.

Terraform resource targeting and explicit replacement both change how an operation handles selected resources, but they solve different problems. -target=ADDRESS narrows the planning graph to selected objects and their dependencies. -replace=ADDRESS asks Terraform to replace particular instances while still planning the configuration as a whole. HashiCorp documents targeting as an exceptional capability for recovering from mistakes or working around limitations, not as a routine way to divide a large configuration into pieces.

The production rule is simple: if you deliberately run a targeted plan, treat it as a temporary recovery step. Review the exact saved plan, understand its dependency closure and omissions, apply only the intended change, and immediately generate a full non-targeted plan to find anything the partial operation did not address. Resume normal automation only after the full plan is reviewed and understood.

What targeting includes and omits

By default, Terraform refreshes managed objects, compares configuration to state, and proposes actions that would bring the managed infrastructure toward the configuration. Resource targeting changes the scope. Terraform selects the addressed resources and extends the selection to objects they depend on, directly or indirectly. It does not automatically include every downstream dependent or every unrelated object that might otherwise change in a full plan.

That asymmetry matters. If resource A depends on B, targeting A includes B because A requires it. Targeting B does not necessarily include every resource that depends on B. The resulting partial plan can temporarily leave configuration and remote infrastructure out of alignment, or omit a change that will be proposed the next time a normal plan runs.

Use the Terraform address that corresponds to the exact resource instance when the target has count or for_each:

terraform state list
terraform plan -target='module.edge.aws_instance.gateway[0]' -out=recovery.tfplan
terraform show recovery.tfplan

An address for a resource with multiple instances selects all instances of that resource. An address with an index or key selects a specific instance. A module-instance target can include resources in that module and its child modules, so module-level targeting can be much broader than a single object. Check the address against terraform state list, then inspect every action in the saved plan before applying it.

Use -target only for a bounded exceptional operation

Appropriate exceptional cases include recovering from a previous partial or failed operation, or working around a known Terraform limitation when an ordinary graph-wide plan cannot make progress. Record the incident, the exact reason targeting is required, the target address, the expected actions, and the full-plan follow-up owner.

Do not routinely target one team or application inside a large root module because its full plan is inconvenient. HashiCorp recommends dividing large systems into smaller independently managed configurations, with explicit interfaces between them, rather than using -target as a permanent operational boundary. A hand-maintained list of target addresses is not equivalent to a well-modeled Terraform stack: it can bypass dependency changes and make configuration drift difficult to see.

Avoid using targeting to suppress an unrelated failure without understanding it. A failure in a provider, data source, or dependency may indicate that a wider part of the plan is not safe to apply. A partial plan can postpone that failure rather than resolve it. If the targeted change changes assumptions for consumers, identify how those consumers will be reconciled afterward.

For an exceptional recovery, the sequence should be explicit:

  1. Freeze competing automation for the same state so no other run changes the plan’s assumptions.
  2. Capture the current workspace, backend, Terraform version, provider lock file, and state identity.
  3. Identify the smallest valid target address from state and configuration.
  4. Generate a saved targeted plan and review all included actions, including dependencies.
  5. Apply the exact reviewed plan, not a newly generated plan with unreviewed differences.
  6. Run a full non-targeted plan and resolve every remaining change or failure.
  7. Record the recovery and remove temporary scripts or target flags from routine automation.

If the full plan shows intended drift, proceed through the normal review and approval process. If it proposes unexpected replacement, deletion, or data migration, stop and inspect the configuration, state, provider behavior, and remote object before applying anything else.

Prefer -replace when an object itself must be recreated

-replace=ADDRESS is the right command-line control when a specific managed instance should be replaced even though its configuration does not independently require replacement. It is useful for an object that has become unhealthy or degraded outside Terraform and should be reprovisioned with the same declared configuration. Unlike targeting, replacement does not mean that Terraform should omit unrelated changes from the plan.

terraform plan -replace='module.edge.aws_instance.gateway[0]' \
  -out=replace-gateway.tfplan
terraform show replace-gateway.tfplan

Review the full plan, because the replacement can still affect dependent resources and the same operation may contain other legitimate configuration changes. The provider’s planned destroy-and-create order, lifecycle rules, immutable fields, and downstream references determine the real disruption. A replacement request does not guarantee zero downtime or health-check completion.

Use -replace only when replacement is the intended operation. It can destroy stateful or expensive objects. Confirm backup and restore requirements, parallel capacity, naming constraints, data retention, and the recovery plan before approval. If Terraform already plans to replace the object due to configuration changes, inspect that replacement directly rather than adding another forced trigger without a reason.

Avoid the deprecated imperative terraform taint workflow for new procedures when -replace meets the need. -replace places the request in the plan itself, so reviewers can inspect it before applying. Still use a saved and reviewed plan for high-impact operations, and remove the flag from scripts after the one-time operation so later applies do not unexpectedly recreate the object.

Targeting and replacement are not interchangeable

Goal Prefer Why
Temporarily apply a carefully isolated part of a graph during a documented recovery -target=ADDRESS Narrows the planned object set and can omit unrelated or downstream changes
Recreate one unhealthy resource using its current configuration -replace=ADDRESS Requests replacement while retaining a full configuration plan
Rename a Terraform address without recreating the remote object A moved block Changes the state address mapping while preserving object identity
Stop managing an object while intentionally preserving it A removed block or documented state handoff Makes ownership transfer explicit instead of disguising it as partial planning
Regularly apply only one service in a monolithic configuration Separate independently managed configurations Establishes durable state and ownership boundaries rather than relying on repeated targeting

The distinction prevents two common incidents: using -target when the desired operation is a replacement, which hides other planned changes; and using -replace to recover from a graph-wide configuration problem, which may create an object without resolving the missing dependency or configuration change.

Save, inspect, and apply the same plan

An operational plan should be tied to the exact state, configuration, backend, and provider selections that were reviewed. Use -out to create a saved plan and terraform show to inspect its proposed actions. If the reviewed plan is no longer valid for the state or current configuration, create a new plan and review it again instead of applying stale intent.

terraform plan -target='module.edge.aws_instance.gateway[0]' \
  -out=recovery.tfplan
terraform show recovery.tfplan
# After the appropriate review and approval:
terraform apply recovery.tfplan

The sample is a workflow pattern, not a recommendation to target an instance. In an incident, use the target address and scope justified by that incident. Restrict access to saved plans because they can contain sensitive configuration values and infrastructure details; use your backend and CI system’s documented artifact controls.

Do not treat a speculative plan from hours earlier as approval for a later apply. A different operator may have changed the remote object, another run may have updated state, or the configuration may have changed. Re-check the final plan against intent, workspace, and state before applying.

Reconcile immediately after a targeted apply

A targeted apply is not the end of the operation. Run an ordinary plan without -target and without a stale -replace flag. The follow-up plan recalculates the full dependency graph and exposes changes that the targeted plan did not include. Do not suppress that plan output or automatically apply it as a continuation of the recovery without reviewing what it proposes.

Compare the plan against the incident’s expected outcome:

  • Is the object healthy and represented at the intended resource address?
  • Did any dependencies or downstream consumers remain out of date?
  • Does Terraform now propose deletion, replacement, or in-place update elsewhere?
  • Did a partial action change outputs, data source results, or assumptions used by another module?
  • Are there pending provider or API errors that were hidden by the limited scope?
  • Does the full plan converge to no changes after the expected configuration is represented?

If Terraform reports no changes, confirm that the service itself is healthy. A no-op plan proves only that Terraform’s observed configuration and state agree under the current provider view; it does not establish application availability or data correctness.

If a full plan continually requires targeted operations, fix the system boundary, provider behavior, dependency model, or state ownership instead of institutionalizing the workaround. Repeated targeting is evidence that the normal plan cannot reliably express or reconcile the system’s desired state.

Production review checklist

  • The operator can explain why a normal full plan is not appropriate for this exceptional action.
  • The address is confirmed from the intended workspace’s current state.
  • The reviewed plan includes the expected target and dependencies and no unexplained action.
  • The team understands which dependents and unrelated changes may be omitted by targeting.
  • -replace is used only when the intended result is resource recreation, not to reduce plan scope.
  • State ownership, locking, workspace, provider versions, and change concurrency are controlled.
  • The same saved plan is reviewed and applied, with any stale plan regenerated and re-reviewed.
  • A full non-targeted plan is run immediately afterward and all remaining changes are explained.
  • Temporary flags and recovery scripts are removed from routine automation.
  • Application health and infrastructure convergence are verified separately.

Terraform’s targeted planning is a useful repair tool precisely because it is not the normal planning mode. Keep its scope small, its purpose documented, and its use temporary. When the incident is resolved, return to a complete plan so the configuration, state, and real system can converge together.

Related:

Sources:

Comments