Terraform Refresh-Only Mode and State Synchronization

Terraform state synchronization is a core operational concern for infrastructure as code teams. The refresh operation reconciles the Terraform state file with the actual resources managed in cloud provider APIs. Modern Terraform handles this reconciliation through refresh-only mode rather than a standalone refresh command.

Introduction

Infrastructure drift occurs when resources are changed outside Terraform, through manual console edits, other automation tools, or deleted resources. Refresh is the mechanism Terraform uses to query real infrastructure and update state to reflect reality. Understanding refresh-only mode is essential for drift detection, state reconciliation, and safe operational workflows without modifying remote objects.

What Terraform Refresh Actually Does

At its core, terraform refresh reconciles Terraform state with the actual infrastructure. It queries cloud provider APIs to get the current state of resources and updates the state to match reality.

The step by step flow is:

  • Terraform reads the current state file
  • For each resource in state, it queries the provider API
  • It compares the actual infrastructure attributes with stored state
  • The state file is updated to reflect real-world values

The terraform refresh command reads the current settings from all managed remote objects and updates the Terraform state to match. This command is deprecated. Instead, add the -refresh-only flag to terraform apply and terraform plan commands.

This does not modify your real remote objects, but it modifies the Terraform state.

Terraform’s refresh command updates the state file by checking the actual infrastructure to reflect any changes made outside Terraform, e.g., manually via the AWS Console. It doesn’t create or modify resources, only syncs the state with the real world.

Terraform refreshes its state by querying the infrastructure to detect any changes made outside of Terraform, manual changes, updates by other tools, etc. This process ensures that the Terraform state file reflects the current state of the infrastructure.

History and Deprecation of the Standalone terraform refresh Command

The standalone terraform refresh command was deprecated in Terraform 0.15.4 but still works.

The terraform refresh command is deprecated due to concerns about unintended state modifications and lack of user control over changes.

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.

The standalone terraform refresh command was deprecated because it modifies state without showing you what changed.

Usage documentation states:

Usage: terraform refresh [options]

This command is effectively an alias for the following command:

terraform apply -refresh-only -auto-approve

Consequently, it supports all of the same options as terraform apply except that it does not accept a saved plan file, it doesn't allow selecting a planning mode other than "refresh only", and -auto-approve is always enabled.

Automatically applying the effect of a refresh is risky.

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.

Refresh-Only Mode Introduced in Terraform 0.15.4

The terraform plan -refresh-only mode was introduced in Terraform 0.15.4 as the replacement for the standalone terraform refresh command.

It lets you update your state file to reflect the current state of your cloud resources without making any changes to those resources. This is essential for drift detection, state reconciliation, and understanding what has changed outside of Terraform.

Modern Terraform uses the -refresh-only flag with plan and apply:

View what would change, recommended approach

terraform plan -refresh-only

Apply refresh changes to state

terraform apply -refresh-only

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.

Normal Plan Versus Refresh-Only Plan

During a normal terraform plan, Terraform:

  • Refreshes state by querying cloud APIs.
  • Compares refreshed state with configuration.
  • Generates a plan to make infrastructure match configuration.

With -refresh-only, Terraform focuses on updating state and root module outputs to match the refreshed remote objects.

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.

Terraform follows a plan-and-apply model to minimise surprises.

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.

How to Use Terraform Refresh-Only

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

terraform init

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

terraform plan -refresh-only

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

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

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.

The refresh command syntax examples include:

Deprecated standalone command

terraform refresh

Refresh with variable file

terraform refresh -var-file="production.tfvars"

Refresh specific target

terraform refresh -target=awsinstance.webserver

Modern usage is:

terraform plan -refresh-only
terraform apply -refresh-only

Targeted Refreshes and Partial State Updates

You can refresh specific resources instead of everything.

Examples:

Only refresh a specific resource

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

Refresh all resources in a module

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

Refresh multiple specific resources

terraform plan -refresh-only \
-target=awsinstance.web \
-target=aws
rds_cluster.database

This is useful for large state files where a full refresh takes a long time, or when you only care about drift in specific resources.

This is the correct behavior - it accurately reflects that the bucket no longer exists.

Drift Detection and Operational Workflows

Refresh-only mode is central to drift detection workflows. Drift detection identifies resources changed outside Terraform.

An example GitHub Actions workflow for drift detection is:

name: Terraform Drift Detection
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
jobs:
check-drift:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
strategy:
matrix:
environment: [dev, staging, prod]
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Terraform Init
run: |
terraform init \
-backend-config="key=${{ matrix.environment }}/terraform.tfstate"
- name: Check for Drift
id: drift
run: |
set +e
terraform plan -refresh-only -detailed-exitcode -no-color > drift-report.txt 2>&1
EXITCODE=$?
set -e
if [ $EXIT
CODE -eq 2 ]; then
echo "driftdetected=true" >> $GITHUBOUTPUT
elif [ $EXITCODE -eq 0 ]; then
echo "drift
detected=false" >> $GITHUBOUTPUT
else
cat drift-report.txt
exit 1
fi
- name: Report Drift
if: steps.drift.outputs.drift
detected == 'true'
run: |
echo "Drift detected in ${{ matrix.environment

Learn how to use terraform plan -refresh-only to update your state file to match actual cloud infrastructure without modifying resources, including drift detection and state reconciliation workflows.

This guide covers when to use refresh-only mode, how it differs from a regular plan, and how to build it into your operational workflows.

Refresh Versus Related Terraform Operations

Terraform’s import command is used to bring existing resources into Terraform’s management. It associates an existing infrastructure resource with a Terraform resource block, allowing Terraform to manage it going forward. It updates the state file but doesn’t modify the resource itself.

You can apply the Terraform refresh by running the terraform apply -refresh=false command. It skips the refresh and applies the plan based on the existing state.

It ensures that the plan reflects the current state rather than the desired state before any changes are made.

A comparison table:

Operation Modifies Remote Objects Modifies State Queries Cloud APIs
terraform plan No No Yes
terraform plan -refresh-only No Shows diff only Yes
terraform apply -refresh-only No Yes Yes
terraform refresh No Yes Yes
terraform apply Yes Yes Yes
terraform import No Yes No

Command options table:

Command Accepts Plan File Planning Mode Auto Approve
terraform refresh No Refresh only Always enabled
terraform apply -refresh-only No Refresh only User controlled
terraform plan -refresh-only No Refresh only N/A

Why Standalone Refresh Was Deprecated

The standalone terraform refresh command was deprecated because it modifies state without showing you what changed.

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.

Automatically applying the effect of a refresh is risky.

With the -refresh-only flag, Terraform ensures that state updates are treated like a change, requiring user approval just like any infrastructure modification.

Conclusion

Terraform refresh-only mode provides a safe, transparent way to synchronize state with real infrastructure. The deprecation of the standalone terraform refresh command in favor of terraform plan -refresh-only and terraform apply -refresh-only reflects a broader principle of plan-and-apply safety. Refresh-only does not modify remote objects, only state, and it makes drift visible before it is accepted.

Operational teams benefit from using refresh-only for drift detection, targeted state reconciliation, and CI/CD pipelines where unintended state changes must be reviewed. Pairing terraform plan -refresh-only with -detailed-exitcode enables automated drift reporting, while -target limits scope for large states. The workflow remains init, plan -refresh-only to inspect, then apply -refresh-only to commit state changes, preserving the same approval model used for infrastructure changes.

Sources

  1. HashiCorp Developer Docs
  2. OneUptime GitHub Blog
  3. TechieLass
  4. Dev.to envzero
  5. OneUptime Blog

Related Posts