Terraform Refresh-Only Mode Reconciling State With Out-of-Band Changes

When an incident forces a manual cloud edit, normal planning proposes to undo it. Refresh-only mode is the narrow tool that absorbs the change into state without proposing any remote actions.

The reader situation

Use case: post-incident reconciliation. An incident forces a security group rule to be widened. An asset tag is added manually so the on-call team can locate a stray resource. An AMI is swapped on a live instance to clear a vulnerability. In each case the remote object no longer matches what Terraform’s state records, and a normal terraform plan proposes to undo the change. Engineers facing this need a way to tell Terraform: accept the new reality, refresh the records, and propose nothing. That is refresh-only mode.

What refresh-only mode actually does

Refresh-only mode creates a plan whose goal is only to update Terraform state and any root module output values to match changes made to remote objects outside of Terraform (terraform plan command). In practice Terraform reads the current remote attributes, writes them into the state file, and the resulting plan reports no resource actions.

Activation, exclusivity, and the apply path

Refresh-only is activated with -refresh-only on either terraform plan or terraform apply; both commands accept the same planning modes when no saved plan is supplied (terraform plan command, terraform apply command). The non-default planning modes are mutually exclusive: activating refresh-only disables the normal planning mode, and you cannot use more than one alternative mode at the same time (terraform plan command). The option is available only in Terraform v0.15.4 and later (terraform plan command).

When terraform apply receives a saved plan file, it honors the decisions in that plan and ignores additional planning modes (terraform apply command). For reconciliation work, the canonical pattern is terraform plan -refresh-only -out=tfplan, then terraform show tfplan to confirm which resource attributes are about to be absorbed into state, then terraform apply tfplan after review. This same two-phase discipline is covered in Speculative vs. Saved Terraform Plans: Making CI Approval Match Execution — for refresh-only, the inspection is a state-scope review rather than a configuration-diff review.

The -refresh=false trap

One flag interaction is worth knowing before you reach for the command. You cannot combine -refresh=false with -refresh-only, because disabling the refresh step would effectively disable the entirety of the refresh-only planning operation (terraform plan command). The refresh is the whole job; skipping it leaves the mode with nothing to do, so the combination is rejected.

State locking still applies

Refresh-only writes state, so it is covered by the same locking rules as any other state-writing operation: locking happens automatically, and if acquiring the lock fails Terraform does not continue (State Locking). Disabling the lock with -lock=false for a refresh-only run is the same anti-pattern as for any other write-state command, because concurrent writers can corrupt state, and the state-locking page discourages that flag explicitly (State Locking).

Operator workflow, not CI gate

Design judgment, not source fact: refresh-only is an operator tool, not a CI step. A pipeline that runs refresh-only before every apply adds work without changing the outcome, because normal terraform plan already refreshes state by default. Reach for refresh-only specifically when a real out-of-band change has produced a divergence and you want to absorb it on purpose, not as routine pre-apply hygiene.

Design judgment: refresh-only accepts whatever the remote says. If both the configuration and the remote have drifted (someone edited main.tf and someone edited the resource), a refresh-only run will not surface the configuration drift. A normal plan is still required to detect that. Use refresh-only only when the configuration is the trusted baseline and only the remote has moved.

Design judgment: because the refresh walks every tracked resource, -refresh-only against a very large configuration with a slow provider API can be slow. Narrowing with -target reduces the scope, but -target is documented as for exceptional circumstances only, with the recommended direction being to split large configurations into smaller, independently applicable ones (terraform plan command).

Summary

Refresh-only mode reconciles Terraform state with out-of-band remote changes without proposing any infrastructure changes of its own. Treat it as a narrow reconciliation tool for incident-driven divergences, respect the -refresh=false incompatibility, let state locking do its job, and use it only when the configuration itself is the trusted baseline.

Law Wen Feng

Cloud and AI Architect in Malaysia. Writes about Azure infrastructure, AI agents, cloud migration, disaster recovery and Microsoft Fabric. More about Law Tech Rants