Terraform Plan Review Checklist Prompt
Review Terraform plan output — read 'destroy', 'replace', 'create', identify dangerous changes, automate review.
- Target user
- Engineers reviewing Terraform plans in MRs
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior Terraform engineer who has reviewed thousands of plans — spotting dangerous changes, dependency cycles, accidental destroys. I will provide: - The Terraform plan output (or summary) - Use case (production, dev, refactor) Your job: 1. **Plan output symbols**: - `+ create` — new resource - `- destroy` — DESTROY (data loss for stateful!) - `~ update` — in-place update - `-/+ replace` — destroy + recreate (data loss for stateful!) - `<= read` — data source query 2. **For dangerous changes**: - Any `destroy` on stateful (database, volume, bucket with data) - Any `replace` on similar - In-place update to immutable field can force replace - Tag-only changes — usually safe 3. **For automated review**: - Parse plan JSON - Flag destroy/replace - Per-resource severity - Block merge on dangerous 4. **For dependency cycles**: - `terraform plan` may hint - Refactor to break cycle 5. **For drift surprises**: - Plan shows changes you didn't write - Possible drift; investigate - Or refresh stale 6. **For external changes**: - Manual change shown as drift - Reconcile: import or destroy 7. **For new providers** in plan: - May indicate config change - Review provider migration 8. **For massive plans**: - "100 resources changing" → maybe wrong target - Use `-target` carefully Mark DESTRUCTIVE: applying plans with destroy on data resources, ignoring drift, automated apply without dangerous-check. --- Plan output: [PASTE summary] Use case: [production / dev / refactor]
Why this prompt works
Plan review is the safety net. This prompt walks the checklist.
How to use it
- Always plan before apply.
- Check destroy / replace count.
- Automate dangerous-detect.
- Approval for prod.
Useful commands
# Plan to file
terraform plan -out=tfplan
# Inspect plan
terraform show tfplan
# JSON output for programmatic review
terraform show -json tfplan > plan.json
# Apply specific plan file
terraform apply tfplan
Plan JSON inspection
# Count operations
jq '.resource_changes | group_by(.change.actions[0]) | map({action: .[0].change.actions[0], count: length})' plan.json
# List destroys
jq -r '.resource_changes[] | select(.change.actions | contains(["delete"])) | "DESTROY: " + .address' plan.json
# List replaces
jq -r '.resource_changes[] | select(.change.actions | (contains(["delete"]) and contains(["create"]))) | "REPLACE: " + .address' plan.json
# Filter by resource type
jq -r '.resource_changes[] | select(.type == "aws_db_instance") | .address + " - " + (.change.actions | join(","))' plan.json
Review checklist
Pre-merge:
[ ] All changes intentional?
[ ] Destroys reviewed (and acceptable)?
[ ] Replaces reviewed (and acceptable)?
[ ] No surprise drift?
[ ] Provider versions match?
[ ] Plan applies cleanly in staging first?
[ ] For prod: separate apply approval?
Dangerous-change detection script
#!/bin/bash
# .gitlab-ci.yml job
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
DESTROY_COUNT=$(jq '[.resource_changes[] | select(.change.actions | contains(["delete"]))] | length' plan.json)
REPLACE_COUNT=$(jq '[.resource_changes[] | select(.change.actions | (contains(["delete"]) and contains(["create"])))] | length' plan.json)
echo "Destroys: $DESTROY_COUNT"
echo "Replaces: $REPLACE_COUNT"
# Block on dangerous patterns
STATEFUL_DESTROYS=$(jq -r '
.resource_changes[] |
select(.change.actions | contains(["delete"])) |
select(.type | test("aws_db_instance|aws_ebs_volume|aws_s3_bucket|aws_dynamodb_table")) |
.address
' plan.json)
if [ -n "$STATEFUL_DESTROYS" ]; then
echo "DANGEROUS: stateful resources scheduled for destroy:"
echo "$STATEFUL_DESTROYS"
exit 1
fi
Reading example plan
Terraform will perform the following actions:
# aws_instance.web will be updated in-place
~ resource "aws_instance" "web" {
id = "i-0abc123def456"
~ instance_type = "t3.small" -> "t3.medium"
tags = {
"Name" = "web-prod"
}
}
# aws_db_instance.main will be replaced
-/+ resource "aws_db_instance" "main" {
~ id = "main" -> (known after apply)
~ db_name = "myapp" -> (known after apply)
~ instance_class = "db.t3.medium" -> "db.r5.large" # forces replacement
- skip_final_snapshot = false -> null
...
}
Plan: 1 to add, 1 to change, 1 to destroy.
Reading:
- Web instance: in-place type bump (safe, brief downtime)
- DB instance: REPLACE due to instance_class — DATA LOSS unless snapshot first
- Action: investigate why instance_class forces replacement; verify backup; consider downtime
Common findings this catches
- Database REPLACE instead of update → check what triggers; backup.
- S3 destroy on bucket with objects → verify lifecycle, recovery.
- Unexpected drift → investigate manual changes.
- Large plan after provider upgrade → review upstream changes.
-targetmasking related changes → carefully scoped.- Plan from different branch → wrong base.
- Apply differs from plan → state changed; re-plan.
When to escalate
- Production destroy/replace — coordinate.
- Massive unexpected drift — investigate.
- Provider major upgrade — staged.
Related prompts
-
Dangerous Terraform Changes Review Prompt
Scan a `terraform plan` output for changes that will silently destroy data, cause outages, or trigger irreversible mutations.
-
Terraform Drift Detection Prompt
Detect Terraform drift — scheduled plans, refresh, drift reporting, alerting, distinguishing manual changes from external mutations.
-
Terraform State Surgery & Import Prompt
Perform Terraform state operations — terraform state mv/rm/import, replace, large-scale imports via import block.