Terraform Refresh State: Reconciling State Drift and Modern Refresh-Only Workflows

Terraform relies on a state file to manage the infrastructure it manages. This state file acts as a source of truth, mapping real-world resources to the configurations defined in Terraform. By maintaining this state, Terraform can determine what changes need to be applied without recreating resources unnecessarily.

When infrastructure is modified through Terraform, the state file remains in sync with the configuration. However, changes can be made directly in the infrastructure interfaces, through PowerShell, CLI, etc and this can be what is called state drift. State drift occurs when the actual infrastructure differs from what Terraform expects. This can lead to unexpected behaviours when new changes are applied via Terraform.

To address this, Terraform provides a way to refresh its state by checking the current status of resources and updating the state file accordingly. The refresh process ensures that the Terraform state file reflects the current state of the infrastructure resources.

What Terraform Refresh Actually Does

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

The step by step process 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

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.

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 manages the infrastructure resources and deployment using the state file. By running the refresh command, you can update the state file with the actual infrastructure configuration.

State Drift and Why Refresh Matters

State drift occurs when the actual infrastructure differs from what Terraform expects. This can lead to unexpected behaviours when new changes are applied via Terraform.

When the resources managed by the Terraform code are sometimes modified using a console, CLI, third-party software APIs, or scripts, the current infrastructure configuration will not match your Terraform code, creating drift because configuration changes were made outside of the regular code-to-cloud CI/CD pipeline.

State drift can be introduced by manual edits, administrative actions, or automated processes that bypass Terraform. Once drift exists, Terraform’s plan will show changes that revert manual edits unless the state is first synchronized.

Refreshing your workspace's state updates Terraform's knowledge of your infrastructure with the current state of your resources as reported by the configured providers. Terraform plan and apply operations run an implicit in-memory refresh as part of their operations, reconciling any drift from your workspace's state before creating a plan for your infrastructure changes.

The Standalone Refresh Command

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

The deprecated standalone command syntax includes:
terraform refresh
terraform refresh -var-file="production.tfvars"
terraform refresh -target=aws_instance.web_server

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.

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.

As of Terraform version v0.15.4, the terraform refresh command was deprecated because its default behavior could be deemed unsafe if you have misconfigured credentials for any of your providers.

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

One concern is that it queries every resource defined in the Terraform configuration, which can be time-consuming for large infrastructures.

Modern Refresh-Only Workflow

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

Recommended approach:
terraform plan -refresh-only
terraform apply -refresh-only

You can also plan and apply updates to your state file without making modifications to your infrastructure using the -refresh-only flag.

In this tutorial, you will identify differences between your workspace's state and your resources using the -refresh-only flag. You will also review Terraform's implicit refresh behavior and the advantages of the -refresh-only flag over the deprecated terraform refresh subcommand.

The -refresh-only flag allows you to view what would change and apply refresh changes to state without modifying real resources.

Refresh vs Apply with Refresh Skipped

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

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.

The -refresh=false option disables the implicit refresh that normally occurs before plan and apply. This is useful when you want Terraform to apply based on existing state without querying providers first.

Practical Example of Detecting Drift

A common scenario is a manual change made outside Terraform.

For example, change the subnet address space from 10.0.1.0/24 to 10.0.2.0/24.

Run the terraform refresh command to query the current state of our resources in Azure (or the respective backend) and update the local Terraform state file to reflect the manual change.

After the refresh, run terraform plan.

Terraform will now detect the difference between the desired state (defined in your main.tf) and the updated state (from the terraform refresh command). It will show an execution plan to revert or adapt the configuration to match the desired state.

This demonstrates how refresh exposes drift so you can decide whether to codify the change or revert it.

Refresh, Import, and State Management

Terraform tracks information about the resources it manages in your workspace's state file. When you apply changes to your resources with Terraform, it creates an execution plan by comparing your workspace's configuration to its current state.

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.

Refresh is different from import. Refresh syncs known resources. Import brings unknown resources under management.

If your Terraform state drifts because changes are made outside of your Terraform configuration, it’s important to make sure you refresh your state file to check the status of resources and update it accordingly so you can move forward with future changes.

Terraform can refresh your state file; this was previously done with the terraform refresh command.

Risks and Considerations

Although terraform refresh command can be a useful diagnostic tool, here are some concerns associated with its usage:

terraform refresh updates the Terraform state file with the current real-world infrastructure state. If resources have been changed outside Terraform (e.g., through manual updates), this could result in unanticipated differences. These changes may later cause Terraform to create, modify, or destroy resources unexpectedly during an apply.

Automatically applying the effect of a refresh is risky.

The standalone refresh command modifies state without showing you what changed. This is why deprecation occurred.

Best practice is to use terraform plan -refresh-only to preview state differences before committing them to state.

Command Comparison

Command Action Modifies Real Infrastructure
terraform refresh Updates state file to match real infrastructure No
terraform plan -refresh-only Shows state differences without updating state permanently No
terraform apply -refresh-only Updates state file to match real infrastructure No
terraform apply -refresh=false Applies plan based on existing state, skips refresh Yes

Workflow Recommendations

When you suspect drift:

Use refresh only mode to sync Terraform state. This keeps changes visible.

Check state before planning to ensure plans reflect reality.

Avoid using the deprecated standalone terraform refresh for production work. Prefer -refresh-only flags.

Be aware that refresh queries provider APIs for every resource in state, which can be time-consuming for large infrastructures.

After a refresh, always run terraform plan to review the resulting drift and decide on corrective configuration changes.

Conclusion

Terraform refresh state is the mechanism that keeps Terraform’s representation of infrastructure accurate when changes occur outside the Terraform workflow. The core function is to reconcile Terraform state with the actual infrastructure by querying provider APIs and updating the state file to reflect real-world values.

The standalone terraform refresh command was deprecated in Terraform 0.15.4 because it modifies state without showing you what changed and can be unsafe with misconfigured credentials. Modern practice replaces it with terraform plan -refresh-only and terraform apply -refresh-only.

Refresh does not create or modify resources, only syncs the state with the real world. It is distinct from import, which brings existing resources under management, and from apply, which modifies real infrastructure.

State drift remains the primary reason to refresh. When infrastructure is changed manually via console, CLI, or third-party tools, Terraform’s state becomes stale. Refreshing updates the state file so subsequent plans accurately represent the gap between desired configuration and actual infrastructure.

The safe workflow is to use -refresh-only to inspect drift, then decide whether to update configuration to match reality or revert the infrastructure to match configuration. Skipping refresh with -refresh=false is available when you intentionally want to apply based on existing state without re-querying providers.

Proper use of refresh state keeps Terraform plans reliable and prevents unexpected create, modify, or destroy actions during apply.

Sources

  1. Dev.to
  2. Techie Lass
  3. OneUptime
  4. Hashicorp Developer
  5. Hashicorp Tutorial
  6. Spacelift

Related Posts