Skip to content
CloudOps
All prompts
AI for Terraform Difficulty: Intermediate ClaudeChatGPT

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

  1. Always plan before apply.
  2. Check destroy / replace count.
  3. Automate dangerous-detect.
  4. 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.
  • -target masking 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

Newsletter

Get weekly AI workflows for DevOps engineers

Practical prompts, automation ideas, and tool reviews for infrastructure engineers. One email per week. No spam.