Terraform Tutorial — State Drift and Conflicts

1 minute read

State drift occurs when someone changes infrastructure outside Terraform (console, CLI, another tool). The state file becomes stale.


Detecting Drift

Run terraform plan — it compares state with reality:

$ terraform plan

  # aws_instance.web has been changed
  ~ resource "aws_instance" "web" {
      ~ instance_type = "t3.micro" -> "t3.small"   # changed outside TF!
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Terraform wants to revert the manual change to match your config.


Option 1: Revert the Drift

If your config is correct and the manual change was a mistake:

$ terraform apply
# Reverts instance_type back to t3.micro

Option 2: Accept the Drift

If you want to keep the manual change, update your config:

resource "aws_instance" "web" {
  instance_type = "t3.small"   # match the manual change
}

Then verify:

$ terraform plan
No changes. Your infrastructure matches the configuration.

Option 3: Refresh State

Update state to match reality without changing config:

$ terraform refresh

Or with plan:

$ terraform plan -refresh-only

⚠️ Warning: terraform refresh updates state but may cause drift between your config and state. Always run plan after refresh.


State Conflict: Resource Deleted Outside Terraform

Error: error reading S3 Bucket: NoSuchBucket: The specified bucket does not exist

Cause: Someone deleted the bucket manually but it’s still in state.

Fix:

# Remove from state (Terraform forgets it)
$ terraform state rm aws_s3_bucket.main

# Then apply to recreate it
$ terraform apply

Preventing Drift

Strategy How
Restrict console access Use read-only roles for developers
Detect drift automatically Run terraform plan in CI/CD on a schedule
Use lifecycle.ignore_changes For attributes managed externally
resource "aws_instance" "web" {
  lifecycle {
    ignore_changes = [tags]  # don't revert tag changes
  }
}

What’s Next?

Let’s handle the case where a resource already exists when Terraform tries to create it.


← Provider Errors Resource Already Exists →