Skip to content
| Marketplace
Sign in
Azure DevOps>Azure Pipelines>Terraform Plan Viewer
Terraform Plan Viewer

Terraform Plan Viewer

Wayne Goosen

|
63 installs
| (2) | Free
Read your Terraform plans like code reviews — module tree, attribute-level diffs, and replace reasons, right in your Azure DevOps build summary.
Get it free

Terraform Plan Viewer

Read your Terraform plans like code reviews, not CLI dumps.

A native Plan Review tab for Azure DevOps build summaries. The task attaches your terraform plan output to the build; the tab renders it as a structured, searchable, themed view — the kind of thing you actually want a teammate to look at before they hit Approve.

Plan Review tab — overview


Why this exists

Most Azure DevOps pipelines do one of two things with a Terraform plan:

  • Dump it as text into the build log — review means scrolling through thousands of ANSI-coded lines and hoping Ctrl+F finds what matters.
  • Generate a static HTML report at pipeline time — locked to one theme, can't be filtered, can't be searched, and goes stale the moment requirements shift.

Neither is built for the moment that matters: a human deciding whether the change is safe to apply.

This extension treats the plan as structured data, not text — so the tab can do everything a code reviewer needs.


What you get

Module-grouped tree, not a flat list

Resources nest by their module address (module.networking.module.subnets). Each module shows rolled-up counts (+1 ~1 −1) so you can read the shape of the change before drilling in.

Attribute-level diffs with replace reasons

Expand any resource and you see exactly which keys changed, before → after, with + - ~ markers. Computed values render as (known after apply). Sensitive values render as (sensitive) — the actual content never reaches your browser.

For replaces ([delete, create]), the tab surfaces the plan's replace_paths — so the question "why is this being recreated?" has a one-line answer instead of a guessing game.

Attribute diff and replace reasons

Click-to-filter summary

Four cards at the top — Create / Update / Recreate / Delete — each with its count and a colored gradient accent. Click one to filter the tree to that action. Click again to clear. Combine with the search box for address / type matching.

Multi-stage pipelines, one tab

Run the task once per stage (dev, staging, prod) with distinct names. The tab lists all attached plans in a dropdown — switching is instant once a plan is loaded, with a skeleton state and named caption (Loading plan: prod…) on first fetch.

The selector hides itself when only one plan is attached, so single-plan pipelines look exactly the same as before.

Outputs section

Output changes are rendered separately. New outputs, removed outputs, and updated outputs each get their own row — so downstream consumers don't get blindsided by a removed connection_string.

Themed for ADO

The tab uses the same CSS theme tokens Azure DevOps uses for the rest of the portal — light mode, dark mode, and high-contrast all just work. Fonts match azure-devops-ui exactly, monospace uses Cascadia Mono (no programming ligatures) so literal attribute values like != and -> render as written.


Quick start

- task: TerraformInstaller@0
  inputs:
    terraformVersion: 'latest'

- task: Bash@3
  displayName: 'Terraform Plan'
  inputs:
    targetType: 'inline'
    script: |
      terraform init
      terraform plan -out=tfplan

- task: TerraformPlanViewer@1
  displayName: 'Publish Terraform Plan'
  inputs:
    planPath: '$(System.DefaultWorkingDirectory)/tfplan'

That's it. Run the pipeline; the Plan Review tab will appear on the build results page.

The task accepts either form of plan:

  • A binary plan (terraform plan -out=tfplan) — converted on the agent via terraform show -json automatically.
  • The JSON form (terraform show -json tfplan > tfplan.json) — useful if you don't have the terraform CLI on the publishing agent.

Using OpenTofu? Binary plans are converted with tofu show -json when terraform isn't on the agent, or set cliTool: 'tofu' to always use it.


Version pinning

TerraformPlanViewer@1 references the major version and automatically picks up the latest minor/patch within major 1 — the recommended form for most pipelines, since you get bug fixes without editing YAML.

Azure DevOps also accepts a complete version, which some supply-chain and SAST policies (e.g. SonarCloud's "Use complete version number" hotspot) require:

- task: TerraformPlanViewer@1.3.0   # full pin = the version shown at the top of this listing

The task version matches the extension version shown at the top of this listing — they're stamped from one source, so the listing number is the number you pin.

Before pinning the full version:

  • The exact version must be installed in your organization. The extension ships one build per major, so only the latest minor/patch is present. Pinning an older build such as @1.0.0 resolves to nothing and the pipeline fails with "task not found" — use the current version from this listing.
  • A full pin is not auto-updating: when a new version publishes you must bump the pin yourself.

Multi-stage example

- task: TerraformPlanViewer@1
  displayName: 'Publish dev plan'
  inputs:
    planPath: '$(System.DefaultWorkingDirectory)/dev/tfplan'
    attachmentName: 'dev'

- task: TerraformPlanViewer@1
  displayName: 'Publish prod plan'
  inputs:
    planPath: '$(System.DefaultWorkingDirectory)/prod/tfplan'
    attachmentName: 'prod'

Each attachmentName becomes a label in the dropdown. Sorted alphabetically, the first is selected by default.


How it works

The task takes your plan file, validates it (binary plans get converted with terraform show -json or tofu show -json), and uploads the JSON as a build attachment with the type terraform-plan-viewer.plan. The tab calls Azure DevOps's Build REST API to download the attachment, parses it client-side, and renders it.

There's no server, no database, no third-party endpoint. Plan data sits in your Azure DevOps organization the same way build logs do.


Privacy & security

  • No third-party calls. Plan JSON lives as a build attachment in your Azure DevOps organization. The tab fetches it from your own ADO API. Nothing leaves your tenant.
  • Sensitive values are masked. Anything Terraform marks as sensitive in before_sensitive / after_sensitive renders as (sensitive) — the underlying value is not rendered to the DOM.
  • DOM-safe rendering. Plan content goes through textContent / createElement, never as an HTML string — so a malicious resource address can't inject script.

FAQ

Do I need the terraform CLI on the publishing agent? Only if you pass a binary plan. Make the CLI that produced the plan (terraform or tofu) available on the agent's PATH; if both are installed, choose it with the cliTool input. If you've already converted to JSON yourself, no CLI is needed.

Will this work with OpenTofu / Terraform Cloud plans? Yes — anything that emits the standard Terraform plan JSON schema works. The tab doesn't care which CLI produced it. For binary OpenTofu plans, the task uses tofu show -json (automatically if terraform isn't installed, or always with cliTool: 'tofu').

My plan is huge. Will it render? The task supports plans up to 256 MiB. The tab parses and renders client-side; multi-thousand-resource plans render in well under a second on modern laptops.

Does it work in dark mode / high-contrast? Yes. All colors use ADO's theme tokens with safe fallbacks.

Can I use this with classic (non-YAML) build pipelines? Yes — the task and tab are both surfaced through the standard build results view, which works in classic and YAML pipelines.


Source, issues, contributions

Open source on GitHub: WayneGoosen/azdo-tf-plan-viewer. Issues and PRs welcome.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft