Terraform Associate: refresh-only plans and drift handling
Refresh-only updates state. It does not apply your configuration.
<!-- hal:authoritative:yaml -->
Refresh-only updates state to match the remote. It does not apply your configuration. Know which plan mode you ran.
§I. Frame: Associate objectives for tonight
10-02 covered encoding functions. 09-29 covered lifecycle meta-arguments. 09-26 covered type constraints. 09-23 covered data sources. 09-20 covered dynamic blocks. 09-17 covered ephemeral. 09-14 covered import/moved. 09-11 covered backends. 09-08 covered check blocks. Leave all of that.
Tonight is planning modes: terraform plan -refresh-only, terraform apply -refresh-only, why the old terraform refresh workflow is retired, and how refresh-only relates to drift in plan JSON (resource_drift, relevant_attributes). Ops ships Azure lifecycle policy. Dev parses the JSON spine.
§II. Three planning modes
| Mode | Flag | Goal |
|---|---|---|
| Normal | (default) | Make remote match configuration |
| Destroy | -destroy | Empty the state by destroying remotes |
| Refresh-only | -refresh-only | Make state (and root outputs) match remotes; do not change remotes to match config |
Named technique: Mode Before Diff. Read the mode line before you read the resource diffs. A refresh-only plan that looks like a delete can be "record that the object is gone or changed," not "destroy it on apply."
HashiCorp added -refresh-only in Terraform 0.15.4+. Associate questions still bait the legacy terraform refresh subcommand.
§III. Why refresh alone was retired
Older workflows ran terraform refresh to rewrite state from remote reads, then planned separately. That command still exists on some versions as a compatibility path, but current docs point operators to refresh-only plans you can review and apply:
terraform plan -refresh-only -out=tfplan-ro
terraform apply -refresh-only # or: terraform apply tfplan-ro
Fact one. Refresh-only apply updates state and root outputs. It does not execute normal create/update/delete from configuration drift toward config.
Fact two. You cannot combine -refresh-only with -refresh=false. Refresh-only is the refresh.
Fact three. Exam trap: "run terraform refresh then apply" is the old story. The current story is a reviewable refresh-only plan.
§IV. Drift on the CLI (credential-free demo)
Using hashicorp/local local_file (no cloud account):
- Apply a file resource with content
alpha. - Edit the file on disk to
beta-external. - Run
terraform plan -refresh-only.
Terraform 1.14.3 reports the object changed outside Terraform. The human UI says this is a refresh-only plan and will not undo the change by rewriting the file to match old state unless you leave refresh-only mode. terraform show -json on that saved plan carries resource_drift and an empty resource_changes list.
That JSON is the Dev spine. Cert only needs the CLI contract: refresh-only is how you choose to record drift into state after review.
§V. Drift vs normal plan
| Question | Refresh-only | Normal plan |
|---|---|---|
| Reads remotes? | Yes | Yes (unless -refresh=false) |
| Writes remotes to match config? | No | Yes, after apply |
| Updates state to match remotes? | Yes, on apply | Also refreshes during plan; apply then converges config |
Plan JSON resource_drift | Often populated | Often populated when refresh sees external change |
Plan JSON relevant_attributes | May be empty | Used to filter which drift may have shaped planned changes |
Rule one. Seeing drift in a normal plan does not mean you must apply a config change. You may need a refresh-only apply first so state matches reality, then a second normal plan.
Rule two. relevant_attributes is the filter Dev uses. Empty index means unmarked drift, not "no drift."
Rule three. -refresh=false on a normal plan skips the remote read. Faster, and blind to external change. Never use it when you are diagnosing drift.
§VI. Exam drills
- Operator changed a tag in the cloud console during an incident. Which command records that tag in state without changing other attributes toward config? →
terraform apply -refresh-only(after reviewingplan -refresh-only). - Can refresh-only destroy a resource because it is absent from
.tf? → No. Absent-from-config destruction is normal/destroy-mode behavior. - Does
terraform refreshremain the documented happy path on current Associate material? → No. Prefer refresh-only plan/apply. - Where do machines read the drift list? →
terraform show -json→resource_drift(and optionallyrelevant_attributes).
§VII. Close
Refresh-only is a planning mode with a reviewable plan file. It reconciles state to remotes. Normal mode reconciles remotes to configuration. Dev classifies resource_drift against relevant_attributes. Ops keeps Azure lifecycle intent declarative so fewer "fixed in portal" drifts appear in the first place.
Related
- Tome: Brikman state chapters — referenced
- Bootcamp: tfpro Lab 22 — referenced
- Docs: plan/apply refresh-only · JSON format · refresh tutorial — grounded-in
- Prior Cert: encoding 10-02 · lifecycle 09-29 · types 09-26 · import/moved 09-14