Terraform State vs. Azure Resource Reality - Behavior Matrix


Quick decision tree (what to do)

  • Have resource in Azure but not in state? → terraform import (Row 4, 8, 13).
  • Have resource in state but not in config (and you want to keep it in Azure)? → terraform state rm (Row 6).
  • Renamed/moved resources in code? → terraform state mv to map old address to new (Row 14–15).
  • Portal edits conflict with .tf? → Let TF overwrite, or add ignore_changes for specific fields (Row 2, 10–11).
  • Plan wants to destroy & recreate but you need continuity? → Check if the change really requires replace; if yes, consider create_before_destroy (when supported), or a migration strategy (Row 9).




#

.tf declares resource?

In state?

Exists in Azure?

Situation / Drift

terraform plan shows

apply result

Typical fix / notes

1

✅

✅

✅

No drift

No changes

N/A

Happy path.

2

✅

✅

✅
(props changed in portal)

Property drift

Update in-place (change block)

Terraform updates Azure to match .tf

Or use lifecycle { ignore_changes = [...] } if portal edits are intentional.

3

✅

✅

❌

Resource missing in Azure

Create (sometimes “replace”)

Terraform recreates resource

If it shouldn’t be recreated, stop and investigate why it disappeared.

4

✅

❌

✅

Unmanaged existing (no state)

Create → will fail (“already exists”)

Error, nothing changed

Import first: terraform import <addr> <id>, then re-plan.

5

✅

❌

❌

New resource

Create

Resource created

Normal create.

6

❌

✅

✅

Orphan in config (still in state & Azure)

Destroy

Terraform deletes from Azure

If you want to keep it but stop managing: use terraform state rm <addr> (removes from state only).

7

❌

✅

❌

Ghost in state (stale state)

Destroy (no remote object, may show replace/destroy)

State entry removed

Safer: terraform state rm <addr> to clean state without trying to destroy.

8

❌

❌

✅

Fully unmanaged (not in config or state)

No-op (Terraform ignores it)

N/A

Either import it to manage, or leave it unmanaged. Consider drift detectors outside TF.

9

✅

✅

✅
(but prop requires replace)

Replace drift (e.g., storage account name, SKU that forces new)

-/+ (destroy & create)

Recreates resource (may cause downtime)

Plan carefully; use create_before_destroy if supported, or schedule a window.

10

✅

✅

✅
(minor portal-only tag drift)

Minor drift

Update (tags)

Tags synced to .tf

If portal is the source of truth for some fields, add ignore_changes.

11

✅

✅

✅
(portal added extra sub-resource)

Partial drift (e.g., extra NSG rule)

Remove/alter sub-resources

Terraform reconciles to match .tf

Import/manage those sub-resources explicitly if you want to keep them.

12

✅

✅

❌
(remote recreated manually with diff ID)

ID drift (state points to non-existent)

Create (new)

New resource created

If Azure has a different object you want: import that instead and remove stale state if needed.

13

✅

❌

✅
(different name than .tf)

Name mismatch

Create → may fail (name taken)

Error

Align names, or import and then refactor .tf with terraform state mv if renaming addresses.

14

✅
(renamed addr)

✅
(old addr)

✅

Address drift (resource moved in code)

Create new + destroy old

Replace (even if same real resource)

Use terraform state mv <old> <new> to avoid churn.

15

✅
(module refactor)

✅
(pre-refactor)

✅

Module/addressing drift

Often large create/destroy plan

Potentially destructive

Map old→new with a series of state mv commands before applying.

16

❌

❌

❌

Nothing anywhere

No-op

N/A

Empty case.

Comments

Popular posts from this blog

Electron Process Execution Failure with FSLogix

KB: Kube-proxy vs CNI Plugin

KB: Azure ACA Container fails to start (no User Assigned or Delegated Managed Identity found for specified ClientId)