Cloud  /  Terraform

IaC Terraform 50 guides · updated 2026

Infrastructure as code done right — providers, state, reusable modules, and the workflow patterns that keep multi-cloud deployments sane in 2026.

Terraform Refresh

Terraform refresh reconciles the local state file with the actual state of infrastructure by querying the provider APIs. Terraform 1.x changed how refresh works — the standalone terraform refresh command is now deprecated in favor of -refresh-only mode built into plan and apply.


The Old Way: terraform refresh (Deprecated)

Terminal window
# Terraform 0.x — standalone refresh command
terraform refresh # Updates state to match real infra, no plan shown
# Problems with this approach:
# 1. Silently modified the state file
# 2. No way to preview what changes would be made to state
# 3. Could accept drift you didn't want to keep

The New Way: -refresh-only (Terraform 1.x+)

-refresh-only makes refresh safe by separating detection from acceptance:

Terminal window
# Step 1: Preview what drift exists (read-only, no changes made)
terraform plan -refresh-only
# Step 2: If you want to accept the drift, update the state
terraform apply -refresh-only

The -refresh-only plan shows only what changed in real infrastructure, not configuration changes — making it a precise drift detection tool.


How Refresh Works During Normal Plan/Apply

Refresh is enabled by default in every terraform plan and terraform apply:

Terminal window
# Default — runs refresh before planning
terraform plan
# Equivalent to:
terraform plan -refresh=true
# Skip refresh (use cached state — faster but might miss drift)
terraform plan -refresh=false

The sequence for a normal terraform apply:

  1. Refresh — query provider APIs to update state with current real-world values
  2. Plan — compare config (desired) against refreshed state (actual)
  3. Diff — compute what changes are needed
  4. Apply — execute the changes
  5. Update state — write the new state after changes

terraform plan -refresh-only

Use this to understand what changed in real infrastructure without modifying it:

Terminal window
terraform plan -refresh-only
# Output shows only real-world changes:
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform
since the last "terraform apply":
~ resource "aws_instance" "web" {
~ instance_type = "t3.micro" -> "t3.small" # Changed in console
}
~ resource "aws_security_group" "app" {
~ ingress = [
# Manually added SSH rule
+ { from_port = 22, to_port = 22, protocol = "tcp", cidr_blocks = ["10.0.0.0/8"] }
]
}
This is a summary of detected drift, not a plan to apply changes.
To update the state to match, run: terraform apply -refresh-only

terraform apply -refresh-only

Accept detected drift by updating the state file:

Terminal window
terraform apply -refresh-only
# Only changes state — does NOT modify real infrastructure
# After this, the state matches what's actually deployed
# Your .tf config now differs from state — update it to match

The typical drift management workflow:

Terminal window
# 1. Detect drift
terraform plan -refresh-only
# 2a. Accept the drift (keep the manual change)
terraform apply -refresh-only
# Then update .tf config to codify the change
# 2b. Reject the drift (restore to Terraform's desired state)
terraform plan # Shows what needs to change to restore config
terraform apply # Restores infrastructure to match config

Skipping Refresh for Speed

Refresh is the slowest part of terraform plan for large configurations — it makes an API call for every resource. Skip it when you’re iterating on config changes and you’re confident no drift occurred:

Terminal window
# Skip refresh — use state as-is, much faster for large configs
terraform plan -refresh=false
# Skip refresh for apply (be careful — state might be stale)
terraform apply -refresh=false

When it’s safe to skip:

When NOT to skip:


Refresh with Targets

For large configurations, refresh only specific resources:

Terminal window
# Only refresh the database instance and its associated security group
terraform plan -refresh-only \
-target=aws_db_instance.main \
-target=aws_security_group.database

Common Refresh Scenarios

Terminal window
# Scenario 1: EKS node group was manually scaled
# Detect and accept the new node count
terraform plan -refresh-only
terraform apply -refresh-only
# Update variables.tf to set the new desired count
# Scenario 2: RDS instance was manually upgraded (instance type changed)
# Detect the change
terraform plan -refresh-only
# Decide: accept (and update .tf) or reject (terraform apply to restore)
# Scenario 3: Route53 record was manually updated
# Check if intentional, then either accept or revert
terraform plan -refresh-only -target=aws_route53_record.api
# Scenario 4: Security group rule was accidentally deleted
# Plan will show Terraform wants to recreate it
terraform plan # Note: not refresh-only — this is a normal plan
terraform apply # Recreate the rule