Skip to content
CloudOps
All guides
AI for Terraform · 7 min read

The Right Way to Pair AI With Terraform Plans

Reviewing a 400-line Terraform plan output is tedious and error-prone. AI helps — but only if you give it the right format and ask the right question.

  • #terraform
  • #ai
  • #plan
  • #review

terraform plan is honest about what it’s going to do. The problem is it’s also verbose, repetitive, and full of cosmetic changes (like recomputed tags) mixed in with real ones (like a database instance scheduled for -/+ replace). On a 400-line plan, the dangerous changes hide.

This is the kind of task AI is actually good at: skimming structured text, flagging the entries that matter, ignoring the rest. But “paste plan into Claude” is not the workflow. There’s a specific shape to this that works.

Why people get this wrong

The natural instinct is to copy the plan output and paste it into a chat:

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"
        ...

The model will respond with a sentence about each line. You’ll scroll. You’ll skim. You’ll miss the -/+ replace on the database because it’s in the middle of 30 routine updates.

This is the same failure mode as pasting a wall of logs and asking “is anything wrong?” The model is too polite to skip things. You need to tell it to.

The format that actually works: JSON

terraform show -json tfplan outputs a structured representation of the plan that’s much easier to reason about than the text format. Two reasons:

  1. The “actions” field is explicit. Each resource_change has a change.actions array — ["create"], ["delete"], ["update"], or ["delete", "create"] for replace. No ambiguity.
  2. You can filter before pasting. With jq, you can extract only the dangerous changes, drop the noise, and feed a 20-line summary into the AI instead of a 400-line plan.

Try this:

terraform plan -out=tfplan
terraform show -json tfplan > plan.json

# Get just the dangerous changes
jq '[.resource_changes[] |
     select(.change.actions | contains(["delete"])) |
     {address, type, actions: .change.actions}]' plan.json

That’s the AI’s input. Compact, unambiguous, and pre-filtered to the changes that need a human decision.

The prompt that catches what plans hide

Once you have the dangerous-changes JSON, the prompt is straightforward:

Here’s a Terraform plan summary showing only delete and replace operations. For each resource, tell me: (1) what data is at risk (none / state but not data / data + state), (2) what triggered the replacement if applicable (look at the change.before vs change.after for the field that forces new), (3) the recommended action — proceed, snapshot first, or block.

The model now has a directed task with three clear outputs per finding. The response is scannable, actionable, and short.

For comparison, the same prompt against the raw text plan produces a wandering essay.

A real example

Here’s a redacted plan summary from a recent change:

[
  {
    "address": "aws_instance.bastion",
    "type": "aws_instance",
    "actions": ["delete", "create"]
  },
  {
    "address": "aws_db_instance.main",
    "type": "aws_db_instance",
    "actions": ["delete", "create"]
  },
  {
    "address": "aws_s3_bucket.logs-old",
    "type": "aws_s3_bucket",
    "actions": ["delete"]
  }
]

Claude’s review of this (paraphrased):

  1. aws_instance.bastion — Replace is fine, no persistent data on bastions. Brief outage of jump-host access (~2 min). Proceed.
  2. aws_db_instance.mainDANGEROUS. Database replace = data loss unless skip_final_snapshot = false and you’ve verified the snapshot will be created. Check the plan JSON for skip_final_snapshot in the change.after — if true, BLOCK. If false, the snapshot will save data but restore is a manual operation. Recommend creating a manual snapshot first regardless.
  3. aws_s3_bucket.logs-old — Delete. If the bucket has objects, this fails by default. If force_destroy = true, all objects are deleted with the bucket. Check the bucket isn’t actively used.

This is exactly the kind of review I want before applying. Without the AI, I’d probably catch the DB replace, but I might miss the force_destroy nuance on the S3 bucket because I’d be in a hurry.

What about Sentinel / OPA / Checkov?

These tools enforce policies — “no public S3 buckets,” “no RDS without deletion protection.” They’re floor-setting. They don’t help with the per-change judgment calls: “is this specific replace acceptable for this specific resource right now?”

I use both. Checkov in CI catches the consistent rule violations. AI review of the plan catches the contextual ones — the cases where a replace is technically allowed but operationally risky.

CI integration

Once this workflow proves out, you can automate it. A simple GitLab CI job:

plan-review:
  stage: review
  needs: [plan]
  image: alpine:3.20
  script:
    - apk add --no-cache jq curl
    - DANGEROUS=$(jq '[.resource_changes[] |
                       select(.change.actions | contains(["delete"]))]' plan.json)
    - |
      if [ "$(echo "$DANGEROUS" | jq length)" -gt 0 ]; then
        echo "Dangerous changes detected, requesting AI review..."
        # Call Claude API with $DANGEROUS as input
        # Post result as MR comment
      fi

This isn’t quite production-ready in two paragraphs of YAML, but the pattern is: detect dangerous changes, send them to AI for contextual review, post the result where the human reviewer will see it.

The point is to make the AI review part of the workflow, not a thing you remember to do. By the time you’re tired enough to miss a replace in a 400-line plan, you also won’t remember to ask AI about it.

What AI can’t tell you about a plan

It can’t tell you whether the change is intended. A replace of a database might be deliberate (you’re migrating engines), in which case the snapshot-first advice is annoying overhead. The AI sees structure; you see intent. The two together is the workflow.

It also can’t tell you whether the change is complete. Sometimes a plan looks safe in isolation but breaks something downstream because of a dependency you forgot about. The AI doesn’t know your downstream dependencies. You do.

The reviewer is still you. The AI is just a fast filter on the parts of the plan that need attention.

For the full prompt set on Terraform safety, see the Terraform category — including terraform-plan-review-checklist and terraform-dangerous-changes-review.

Newsletter

Get weekly AI workflows for DevOps engineers

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