The plan says three to destroy, and you only removed one — cheat sheet
terraform
# read before you change
terraform plan # the diff between config, state and reality
terraform plan -out=change.plan # save it…
terraform show change.plan # …review it…
terraform apply change.plan # …apply exactly that ("Saved plan is stale" if state moved)
terraform plan -destroy # what destroy would touch
terraform plan -detailed-exitcode # exit 0 no changes, 1 error, 2 changes — for drift checks
# state is identity
terraform state list # every managed address
terraform state show 'random_password.db["alice"]'
# address = TYPE.NAME[index] (count) or TYPE.NAME["key"] (for_each)
# refactoring safely
# moved { from = random_password.db[0] to = random_password.db["alice"] }
# plan until: Plan: 0 to add, 0 to change, 0 to destroy.
# count vs for_each
# count = var.enabled ? 1 : 0 ← how many
# for_each = toset(var.users) ← which ones (each.key / each.value)
# guards
# lifecycle { prevent_destroy = true } ← fails any plan that destroys it; gone if the block is deleted
# lifecycle { create_before_destroy = true } ← replacement creates the new one first
# lifecycle { ignore_changes = [tags] } ← tolerate drift in named attributes
# secrets
terraform output # sensitive values shown as <sensitive>
terraform output NAME # …but printed in full when asked by name
# terraform.tfstate and .backup: plain text, every attribute — never in git