skip to content

In Terraform, what do `terraform plan -refresh-only` and `terraform apply -refresh-only` do, and when would you reach for them?

level: middleimportance: should knowfreq 52%

answer

  1. reads reality, proposes state changes only
  2. never creates, updates or destroys
  3. replaced the deprecated standalone refresh command
  4. state gets fixed, config does not
  5. preview then approve, like any other apply

basics

~20 s

A refresh-only run re-reads real infrastructure and proposes updates to the Terraform state file only — never to infrastructure. Plan shows what drifted; apply writes those observed values into state, leaving the configuration and the real resources untouched.

solid answer

~50 s

`terraform plan -refresh-only` refreshes state from the provider and then reports only one kind of change: how the recorded state differs from reality. It never proposes creating, updating or destroying anything. `terraform apply -refresh-only` performs the same refresh and, after you approve, writes those observed values into the state file — again touching no infrastructure. I use it to answer "what changed behind our backs?" without any risk of a stray apply, and to accept a legitimate out-of-band change into state before deciding what to do about the configuration. It also replaced the old standalone `terraform refresh` command, which was deprecated in 0.15.4 precisely because it wrote state with no preview and no approval step. The important limitation: refresh-only updates state, not your `.tf` files, so the very next normal plan still wants to reconcile config with what it just recorded.

code

bash · 8 lines
bash
# Investigate: what changed outside Terraform? (cannot alter infrastructure)
terraform plan -refresh-only -input=false -no-color

# Accept those observations into state, still touching no infrastructure
terraform apply -refresh-only -input=false -auto-approve

# Config is unchanged, so this normal plan may now want to reconcile it
terraform plan -input=false -no-color

go deeper

for a junior

Recall that a refresh-only run only updates Terraform's record of the world and never changes real resources, which makes it the safe command to run when you just want to look.

for a middle

Explain that plan -refresh-only reports state-versus-reality differences, apply -refresh-only writes them into state after approval, and that neither touches the configuration files.

for a senior

Demonstrate when you reach for it under pressure: investigating an out-of-band change during an incident, or separating someone else's drift from your own diff before approving a risky apply.

for a principal

Own the norm around it. Decide who may accept drift into state, whether refresh-only applies need review, and how the team is required to follow up with a config change rather than leaving state as the only record.

## Two things that sound the same and are opposites Terraform has two refresh-related flags that are easy to confuse: - `-refresh=false` — do the diff, but **skip** reading reality. - `-refresh-only` — read reality, and skip **everything else**. A refresh-only run is a deliberately narrowed plan: the only actions it can propose are updates to the state file. It cannot create, update or destroy a real resource, which is why it is safe to hand to someone who is nervous about running Terraform at all. ## What `plan -refresh-only` reports It performs the ordinary refresh — one provider read per resource instance in state — and then prints the differences it found between what state recorded and what the API returned. Typical output opens with a note that objects have changed outside of Terraform, followed by attribute-level before/after pairs, and ends by telling you this plan would only update state. That is the concrete, Terraform-specific way to answer "did anyone touch prod?" It is strictly read-only against the backend as well: like any plan, it does not persist the refreshed values. ## What `apply -refresh-only` does Same refresh, then a prompt, then a state write. After approval, state contains the observed values. Nothing in the cloud changes. Two situations make this worth doing: 1. **The out-of-band change is legitimate and staying.** Someone bumped an instance size during an incident and the team agrees to keep it. Recording it in state first means the follow-up config edit is being written against an accurate baseline. 2. **State has drifted into inconsistency** — for example a resource was deleted out of band and you want state to reflect that before you plan, so the plan proposes a clean create instead of a confusing update. ```bash terraform plan -refresh-only # what changed behind our backs? terraform apply -refresh-only # record it in state, prompt to approve terraform apply -refresh-only -auto-approve # same, unattended ``` ## Why the standalone command went away Before 0.15.4, `terraform refresh` did the state update directly with no preview and no approval. Silently rewriting the single most important file in the workflow, with no diff to look at, was a bad shape — so it was deprecated and its behaviour re-expressed as `terraform apply -refresh-only -auto-approve`. Now the state write goes through the same plan-review-approve loop as everything else. Expect an interviewer to ask what you would run "instead of `terraform refresh`", and answer with the refresh-only apply. ## The limitation that catches people Refresh-only touches **state**, never **configuration**. Your `.tf` files still say what they always said. So after you accept a console change into state, the next normal plan sees config and state disagree and proposes to change the resource back to the configured value. Accepting drift into state is not the same as blessing it — that second step is a code edit and a review. ## Where it fits in a workflow - **Investigating an incident:** refresh-only plan first, because it cannot possibly change anything. - **Before a risky apply:** a refresh-only plan tells you whether reality still matches assumptions, separating "my change" from "someone else's change" in the diff you are about to approve. - **Cleanup after manual intervention:** record what the console did, then decide as a team whether the code adopts it or the next apply reverts it. ## What to say out loud Refresh-only is Terraform's read-the-world-without-touching-it mode: `plan -refresh-only` shows how state differs from reality, `apply -refresh-only` writes those observations into state, both leave infrastructure alone, and neither edits your configuration — so the reconciliation with the code is still a separate, deliberate step.

  • What should you run now that the standalone `terraform refresh` command is deprecated?
    `terraform apply -refresh-only`, adding `-auto-approve` for the unattended equivalent. The deprecation was about shape, not capability: the old command rewrote state with no preview and no approval, while the refresh-only apply shows you a diff of the state changes first and asks before writing.
  • Can a refresh-only apply damage anything?
    It cannot change infrastructure, but it can change state, and state is not disposable. Accepting a bad refresh — for example while a provider is returning throttled or partial reads — records wrong values, and a later plan acts on them. Run the refresh-only plan first and read the diff rather than reflexively auto-approving.
  • Does `terraform apply -refresh-only` also update your .tf files to match reality?
    No. It only writes state. Configuration is authored by humans, so after accepting drift into state you still choose: edit the code to match the new reality, or let the next normal apply push the resource back to what the code says. Refresh-only records the fact, it does not settle the argument.

saying these in an interview costs you the question

  • Thinks refresh-only can also create or destroy resources
  • Believes refresh-only rewrites the .tf configuration to match reality
  • Confuses -refresh-only with -refresh=false
  • Says terraform refresh is still the recommended command
  • Assumes accepting drift into state means the drift is now permanent

context