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=awsrds_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 [ $EXITCODE -eq 2 ]; then
echo "driftdetected=true" >> $GITHUBOUTPUT
elif [ $EXITCODE -eq 0 ]; then
echo "driftdetected=false" >> $GITHUBOUTPUT
else
cat drift-report.txt
exit 1
fi
- name: Report Drift
if: steps.drift.outputs.driftdetected == '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.