Terraform Plan Noise Reduction & Refresh Strategy Prompt
Kill perpetual-diff noise in Terraform plans — refresh strategy, ignore_changes, provider default drift, and -refresh=false trade-offs.
- Target user
- Platform engineers tired of noisy, untrustworthy plans
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a senior Terraform engineer who has spent years making large plans trustworthy again — turning "50 resources changing every run" back into clean, honest diffs.
I will provide:
- A noisy `terraform plan` excerpt (or `terraform show -json` output)
- Provider(s) and versions
- Where it runs (local, CI, Terraform Cloud)
- What "should" be changing (ideally nothing)
Your job:
1. **Classify every noisy diff** into one of:
- **Perpetual diff** — same attribute flips every run (provider normalizes a value, computed default, ordering).
- **Real drift** — something changed outside Terraform.
- **Stale state** — state is behind reality; a refresh would reconcile it.
- **Config bug** — a `null` vs `""`, list ordering, or interpolation that never settles.
2. **For perpetual diffs**, recommend the narrowest fix:
- `lifecycle { ignore_changes = [specific.attr] }` (never a blanket `all` unless justified).
- Setting the attribute explicitly to the value the provider computes.
- Provider upgrade if it is a known normalization bug (cite the behavior, not a version guess).
3. **Refresh strategy** — reason about the trade-offs, do not cargo-cult:
- `-refresh=false` speeds plans and hides real drift; when is that acceptable (fast PR previews) vs dangerous (pre-apply gate)?
- `-refresh-only` to reconcile state without proposing config changes.
- `-target` to scope a refresh when full refresh is slow or rate-limited.
4. **Ordering / set-vs-list noise** — spot attributes that are unordered sets modeled as lists, and recommend the schema-correct fix.
5. **known-after-apply cascades** — identify when one computed value forces a chain of "(known after apply)" and whether it is real or an artifact of `-target`/refresh gaps.
6. **CI implications** — how the refresh choice interacts with concurrency, provider rate limits, and plan/apply drift between the two stages.
For each recommendation give: the exact HCL or CLI change, the blast radius, and how to confirm the noise is gone (a clean second plan).
Mark DESTRUCTIVE: `ignore_changes` that would mask a real security-relevant change (IAM, security groups, public access), and `-refresh=false` on the pre-apply gate.
---
Noisy plan: [PASTE excerpt or plan JSON]
Providers/versions: [DESCRIBE]
Runs in: [local / CI / TFC]
Expected changes: [ideally none]
Run this prompt with AI
Test it, get an AI-improved version, or compare models — live in the Prompt Workspace. No copy-paste.
Why this prompt works
A plan that always shows changes trains engineers to stop reading plans — the single most dangerous habit in IaC. This prompt forces a diagnosis (perpetual diff vs real drift vs stale state vs bug) before any fix, so you do not silence a real change by reflex.
How to use it
- Capture the noise as plan JSON, not a screenshot.
- Classify each diff before touching config.
- Apply the narrowest fix and prove it with a clean second plan.
- Revisit refresh strategy for CI separately from local.
Useful commands
# Machine-readable plan for classification
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
# Reconcile state with reality WITHOUT proposing config changes
terraform apply -refresh-only
# Fast preview that skips refresh (PR comment only, never the gate)
terraform plan -refresh=false -out=tfplan
# Scope a slow/rate-limited refresh
terraform plan -target=module.slow_thing
Triage the noise
# Every non-no-op change, with its actions
jq -r '.resource_changes[]
| select(.change.actions[] != "no-op")
| "\(.change.actions | join(",")) \(.address)"' plan.json
# Attributes that are flipping (candidate perpetual diffs)
jq -r '.resource_changes[]
| select(.change.actions[] == "update")
| .address as $a
| (.change.before // {}) as $b
| (.change.after // {}) as $af
| ($af | keys[])
| "\($a): \(.)"' plan.json | sort | uniq -c | sort -rn
Narrow ignore_changes (perpetual diff)
# BAD: blinds Terraform to everything, including real changes
# lifecycle { ignore_changes = all }
# GOOD: silence only the attribute the provider normalizes
resource "aws_ecs_service" "api" {
# ...
lifecycle {
ignore_changes = [
task_definition, # updated out-of-band by the deploy pipeline
desired_count, # managed by application autoscaling
]
}
}
Set-vs-list ordering noise
# A perpetual diff often means an unordered value is modeled as an ordered list.
# Convert to toset() so ordering stops mattering.
resource "aws_security_group" "web" {
name = "web"
dynamic "ingress" {
for_each = toset(var.allowed_ports) # set, not list
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
}
}
}
Refresh strategy decision table
Context Refresh choice Why
------------------------------ ---------------------- --------------------------------
PR preview comment -refresh=false Fast, no drift-guard needed here
Pre-apply gate (main) full refresh (default) Must see real drift before apply
State behind reality -refresh-only apply Reconcile without config changes
Slow/rate-limited provider -target refresh Scope, then full plan before apply
Nightly drift job -detailed-exitcode Exit 2 = drift, alert on it
Common findings this catches
json/policystring diffs that never settle → normalize withjsonencode().- Tag drift from a cost tool →
ignore_changes = [tags["CostCenter"]]. (known after apply)cascades caused by-target, not real change.-refresh=falseon the apply gate silently applying stale plans.- List vs set ordering churn on rules and blocks.
When to escalate
- Noise that is actually real drift in security resources → incident, not
ignore_changes. - A provider normalization bug with no clean workaround → pin/upgrade and file upstream.
- Plan/apply state mismatch in CI → fix pipeline ordering before shipping.
Related prompts
-
Terraform Plan Review Checklist Prompt
Review Terraform plan output — read 'destroy', 'replace', 'create', identify dangerous changes, automate review.
-
Terraform Drift Detection Prompt
Detect Terraform drift — scheduled plans, refresh, drift reporting, alerting, distinguishing manual changes from external mutations.
-
Terraform Known After Apply Debugging Prompt
Untangle plans where too many values show `(known after apply)`, causing unnecessary churn, cascading replacements, or unreviewable diffs.
-
Terraform replace_triggered_by Design Review Prompt
Design and audit lifecycle replace_triggered_by rules so intentional replacements fire correctly without causing surprise destroy/recreate cascades.
More Terraform prompts & error guides
Browse every Terraform prompt and troubleshooting guide in one place.
Reading prompts? Get all 500 in one free PDF
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.