Terraform Apply Refresh Only: Safe State Reconciliation Without Infrastructure Changes

Terraform state drift is one of the most common sources of surprise in infrastructure as code. When resources are changed outside of Terraform, manually, via a console, or by another automation system, the state file no longer reflects reality. Terraform Apply Refresh Only provides a controlled way to reconcile state with live infrastructure without making configuration changes. It preserves the plan-and-apply safety model while allowing operators to preview and approve state updates.

Introduction

The traditional workflow for detecting drift relied on a standalone refresh subcommand. As of Terraform 0.15.4, this command has been deprecated due to concerns about unintended state modifications and lack of user control over changes. Instead, Terraform has introduced the command terraform plan -refresh-only or terraform apply -refresh-only. With this approach, you can run the terraform plan -refresh-only you can see the plan showing exactly what Terraform detects as different in the infrastructure compared to its current state. You can review these differences before deciding whether to apply them.

In contrast, the old terraform refresh command would immediately update the state file without showing you the changes first, potentially leading to unexpected updates that were difficult to track. Terraform follows a plan-and-apply model to minimise surprises. The -refresh-only flag fits into this model by ensuring that state updates are treated like a change, requiring user approval just like any infrastructure modification.

This structured approach is particularly useful in team environments or CI/CD pipelines, where unintended state changes can lead to confusion or conflicts.

What Refresh Only Mode Does

It allows you to update your Terraform state to match the real infrastructure without applying any configuration changes.

Traditional Refresh vs Refresh-Only Mode

Traditional Refresh is the old method that directly modifies state.

  • terraform refresh
  • Modifies state immediately without review
  • No plan preview of state changes
  • Can cause unexpected side effects
  • No rollback capability

Refresh-Only Mode is the new safe state updates method.

  • terraform plan -refresh-only
  • terraform apply -refresh-only
  • Shows what will change before applying
  • No infrastructure modifications
  • Can be reviewed and approved
  • Safer for production environments

The -refresh-only mode for terraform plan and terraform apply operations makes it safer to check Terraform state against real infrastructure by letting you review proposed changes to the state file. It lets you avoid mistakenly removing an existing resource from state and gives you a chance to correct your configuration.

A refresh-only apply operation also updates outputs, if necessary. If you have any other workspaces that use the terraformremotestate data source to access the outputs of the current workspace, the -refresh-only mode allows you to anticipate the downstream effects.

When to Use Refresh Only Mode

Refresh only mode is useful for several operational scenarios.

  • Drift Detection: Check if infrastructure matches state
  • State Reconciliation: Update state after manual changes
  • Import Follow-up: Refresh state after importing resources
  • Regular Maintenance: Periodic state cleanup
  • Troubleshooting: Resolve state inconsistencies

In order to propose accurate changes to your infrastructure, Terraform first attempts to reconcile the resources tracked in your state file with your actual infrastructure. Terraform plan and apply operations first run an in-memory refresh to determine which changes to propose to your infrastructure. Once you confirm a terraform apply, Terraform will update your infrastructure and state file.

Basic Workflow

Before running any commands, ensure that Terraform is initialised and has access to the state file by running the command:

bash terraform init

Then run the following command to compare the current infrastructure with the state file by running:

bash terraform plan -refresh-only

This command checks for differences between the expected configuration and the actual deployed resources.

You can see in the example screenshot below when I run the command it’s compared what the settings should be against what I have within my live Azure environment and highlights some changes.

To update the Terraform state file without modifying any resources, run:

bash terraform apply -refresh-only

This refreshes the state file to reflect the actual environment, ensuring that future Terraform changes are based on the correct resource configurations. This is particularly useful before making further updates to your resources, as it prevents unintended modifications due to outdated state data.

Step by Step Preview and Apply

Step 1: Preview State Changes

Check what state changes would occur.

bash terraform plan -refresh-only

Example output:

```
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":

aws_instance.web has changed

~ resource "awsinstance" "web" {
id = "i-1234567890abcdef0"
~ instance
type = "t2.micro" -> "t2.small"

(29 unchanged attributes hidden)

}
```

This is a refresh-only plan, so Terraform will not take any actions to undo these. If you were expecting these changes then you can apply this plan to record the updated values in the Terraform state without changing any remote objects.

Step 2: Apply State Updates

Apply the state changes.

bash terraform apply -refresh-only

Example output:

Apply complete

The refresh operation with remote state behaves the same but with additional considerations. When using remote backends like S3 or Terraform Cloud, refresh behaves the same but with additional considerations:

hcl terraform { backend "s3" { bucket = "my-terraform-state" key = "prod/terraform.tfstate" region = "us-east-1" use_lockfile = true } }

The refresh operation:
- Acquires state lock (if locking is enabled)
- Downloads current state from S3
- Queries provider APIs
- Updates state
- Uploads new state to S3
- Releases lock

Safe Practices for Refresh Only

Always Preview First

Never apply refresh without reviewing.

Bad:

bash terraform apply -refresh-only -auto-approve

Good:

bash terraform plan -refresh-only

Review output carefully

bash terraform apply -refresh-only

Use Plan Files for Important Changes

For production or critical changes:

bash terraform plan -refresh-only -out=prod-refresh.plan

Have team review plan

bash terraform show prod-refresh.plan

Apply after approval

bash terraform apply prod-refresh.plan

Document Refresh Decisions

```bash

!/bin/bash

Document why refresh was needed

echo "State refresh performed on $(date)" >> refresh.log
echo "Reason: Manual instance type change for performance" >> refresh.log
echo "Resources affected: aws_instance.web" >> refresh.log
echo "Applied by: $(whoami)" >> refresh.log
echo "---" >> refresh.log
terraform plan -refresh-only -out=refresh.plan
terraform apply refresh.plan
```

Here are some best practices that I have started incorporating into my Terraform workflow:
- Run terraform plan -refresh-only before every apply, this helps to flag up any issues with drift and prepare me to update my state file if needed before making any resource modifications.
- Review changes before applying, if any changes are flagging up I make sure I review the changes before updating my state to understand why the changes have occurred.

The -refresh-only flag is an important one that you should be aware of to ensure your Terraform state files are kept up to date and help to prevent any unintended changes to your resources.

Partial Refresh and Targeting

For large infrastructures, refresh specific resources:

bash terraform plan -refresh-only -target=aws_instance.web

bash terraform plan -refresh-only -target=module.networking

Partial refresh with targets reduces API calls and narrows the review scope.

Combining Refresh With Configuration Updates

Workflow for handling drift:

Step 1: Detect drift

bash terraform plan -refresh-only

Step 2: Update state

bash terraform apply -refresh-only

Step 3: Decide on configuration

Either update config to match state or plan to revert

Step 4: Apply final configuration

bash terraform plan terraform apply

This sequence separates state reconciliation from configuration enforcement.

Skipping Refresh

You can skip it:

bash terraform plan -refresh=false

Skip refresh during plan (use cached state)

bash terraform apply -refresh=false

Skip refresh during apply

Use this cautiously - your state might not reflect reality.

Common Refresh Scenarios

Scenario 1: Import Existing Resources

After importing resources, refresh ensures complete state:

bash terraform import aws_instance.imported i-1234567890abcdef0

Refresh to get all attributes

bash terraform apply -refresh-only

Scenario 2: After Provider Upgrades

Provider upgrades may change how attributes are stored:

bash terraform init -upgrade terraform plan -refresh-only

Scenario 3: Debugging State Issues

When state seems corrupted or outdated:

Check what Terraform thinks vs

Risks of the Deprecated Command

However, this was less safe than the -refresh-only plan and apply mode since it would automatically overwrite your state file without giving you the option to review the modifications first. In this case, that would mean automatically dropping all of your resources from your state file.

Though Terraform will continue to support the refresh subcommand in future versions, it is deprecated, and we encourage you to use the -refresh-only flag instead. This allows you to review any updates to your state file.

Comparison Table

Feature terraform refresh (deprecated) terraform plan -refresh-only / apply -refresh-only
State update timing Immediate Preview then apply
Infrastructure changes None None
Review before apply No Yes
Rollback capability No Yes via plan file
Safe for production No Yes
Updates outputs No Yes

Conclusion

Terraform Apply Refresh Only is the controlled path to keep state truthful without risking unintended resource modifications. By replacing the immediate overwrite behavior of the deprecated terraform refresh command with a plan-and-apply review cycle, teams gain visibility into drift, can document why state was updated, and can approve changes through plan files before any state mutation occurs.

The workflow of running terraform plan -refresh-only before every apply, reviewing detected differences, and then running terraform apply -refresh-only to record them ensures that subsequent plans are based on real infrastructure. When combined with targeting, remote state locking, and documentation practices, refresh only mode provides a repeatable safety net for manual changes, imports, provider upgrades, and periodic maintenance.

Adopting refresh only mode as a standard step in CI/CD pipelines and team runbooks reduces surprise drift, preserves auditability, and aligns state reconciliation with the same approval gates used for infrastructure changes.

Sources

  1. dev.to techielass article
  2. asklearn terraform course
  3. oneuptime blog
  4. hashicorp developer tutorial

Related Posts