返回博客

博客

Terraform Graph Visualization: From Spaghetti to Diagram

Terraform graph visualization humans can read: clean up terraform graph output, add plan and state data, then build a real architecture diagram.

terraform graph visualization更新于 2026/11/5Shafi Khan

Terraform Graph Visualization: From Spaghetti to Diagram

Terraform graph visualization, the short version: run terraform graph | dot -Tsvg > graph.svg to render your dependency graph, then pipe it through tred to cut the noise. That gets you a correct build order. It doesn't get you an architecture diagram, because Terraform's arrows mean "depends on", not "sends traffic to".

Everyone tries it once. You run the command, open the SVG, and get a plate of boxes and lines that reads like a subway map drawn during an earthquake.

The command isn't broken. You're asking it a question it was never built to answer. Here's what each Terraform view really tells you, how to make the output readable, and how to get from there to a diagram a reviewer can trust.

What terraform graph visualization actually shows

By default, terraform graph outputs a simplified graph of the dependency ordering between resource and data blocks. That's the graph Terraform uses to decide what to do first, not a map of your system.

Terraform's dependency graph docs explain where the edges come from: references between resources, plus explicit depends_on. So an arrow points from the thing doing the referencing to the thing being referenced.

That one detail breaks most first attempts. A listener references its load balancer, so the arrow runs listener to load balancer. Traffic flows the other way. Read the graph as a network diagram and it's confidently, beautifully wrong.

Terraform gives you four separate views of the truth, and each answers a different question:

QuestionWhere to lookCommandWhat it can't tell you
What depends on what?Configurationterraform graphTraffic, trust zones, anything unmanaged
What does Terraform think it manages?Stateterraform state listWhether reality still matches
What will this change do?Planterraform show -json tfplanWhether the design is any good
What changed outside Terraform?Refresh-only planterraform plan -refresh-onlyResources Terraform has never tracked

Pick the view that matches your question and half the pain disappears.

→ Explore your Terraform modules with architecture context in IaC Orchestration

Terraform graph to SVG: make the output readable

The basic version takes two commands. You'll need Graphviz installed, because Terraform prints DOT text rather than an image:

terraform init
terraform graph | dot -Tsvg > graph.svg

Now the upgrades. tred is a Graphviz filter that does transitive reduction: if A depends on B, and B depends on C, a direct A to C edge is redundant, so it goes. On a real config this removes a surprising amount of visual noise. Left-to-right layouts also tend to suit long resource names:

terraform graph | tred | dot -Tsvg -Grankdir=LR > graph-clean.svg

Keep one caveat in mind: tred hides redundant dependency edges, so use the reduced picture for reading and the full output for debugging.

A few more flags are worth knowing:

GoalCommand
See the detailed plan graph, including runtime internalsterraform graph -type=plan | dot -Tpng > plan.png
Draw the graph for one saved planterraform graph -plan=tfplan | dot -Tsvg > apply.svg
Debug a cycle errorterraform graph -type=plan -draw-cycles | dot -Tsvg > cycles.svg
Pass variablesterraform graph -var-file=prod.tfvars | dot -Tsvg > prod.svg

Two gotchas. -draw-cycles only works with a real graph type, so it needs -type. And the detailed types expose implementation details of the Terraform runtime, so a bigger graph isn't automatically a more useful one. For everyday reading, stick with the default.

For a fast read on a module you've just inherited, paste the HCL into the Terraform Module Visualizer. It runs in your browser and returns counts, a resource inventory and a starter Mermaid topology. Treat it as a scoping tool: it reads the text you paste, so it won't resolve variables, count or remote modules, and its topology isn't a dependency graph.

→ Paste your HCL into the free Terraform Module Visualizer

How to visualize Terraform state and plans

The dependency graph can't show you what's deployed or what's about to change. For that, go to state and plan data.

Visualize Terraform state

Start with terraform state list, which prints one resource address per line. Root resources come first, deeper modules last, and you can filter by module:

terraform state list
terraform state list module.network

It's simple, and for "what does this workspace own?" it often beats any picture. Need structured data for a script? terraform show -json gives you the latest state snapshot as JSON.

Terraform plan visualization with jq

Before a risky apply, reviewers want a list of what's changing and how. Save the plan, convert it, then ask for exactly that:

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

jq -r '.resource_changes[]
  | select(.mode == "managed")
  | "\(.change.actions | join("+"))\t\(.address)"' plan.json

You'll get one line per resource instance:

no-op           aws_lb.public
update          module.net.aws_subnet.a
delete+create   aws_db_instance.main

That last line is the one to circle in red. The JSON output format represents a replacement as an action pair, either delete then create or the reverse, so scanning for delete catches every destructive change.

The same JSON can also build a smaller, reference-only graph of your root module:

jq -r '
  [ .configuration.root_module.resources[]
    | .address as $from
    | .expressions | .. | .references? // empty | .[]
    | select(test("^(data\\.)?[a-z0-9_-]+\\.[a-zA-Z0-9_-]+$"))
    | select(test("^(var|local|path|terraform|each|count|self)\\.") | not)
    | "  \"\($from)\" -> \"\(.)\";"
  ] | unique | "digraph refs {", .[], "}"
' plan.json | dot -Tsvg > refs.svg

This drops variables and locals, keeps module calls as single nodes, and only walks the root module. It's a one-off reading aid, not production tooling: the docs tell callers to stick to string equality on references, because the syntax may be extended. Don't build CI on that regex.

Heads up: saved plans can hold sensitive data in cleartext, even when the terminal output hides it. terraform show -json also prints sensitive state values in plain text. Don't paste plan.json into a random web tool or leave it lying around as a public CI artifact.

→ Bring Terraform and state into a tracked import with IaC Import

Worked example: the arrow your graph will never draw

Here's why a clean graph still isn't architecture. Take a standard three-tier app, trimmed to the interesting bits:

resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.public.arn
  port              = 443
  protocol          = "HTTPS"
  certificate_arn   = var.certificate_arn

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.app.arn
  }
}

resource "aws_vpc_security_group_ingress_rule" "db_from_app" {
  security_group_id            = aws_security_group.db.id
  referenced_security_group_id = aws_security_group.app.id
  from_port                    = 5432
  to_port                      = 5432
  ip_protocol                  = "tcp"
}

Compare what the graph says with what a reviewer needs to know:

Reviewer's questionWhat the graph showsWhat the diagram must show
How do users reach the app?Listener points at the load balancer and target groupUser to load balancer on 443, then to the app tier
Does the app talk to the database?Both security groups connect through a rule nodeApp to database on 5432, labelled as allowed
Which tier is public?Nothing, subnets are just nodesA boundary around the public tier
What about the payment provider?Nothing, it isn't a Terraform resourceAn external system with a labelled egress path

The database row is the sneaky one. If the app reads its database hostname from a secret at runtime, there may be no Terraform reference between the app and the database at all. The dependency that matters most to your 3 a.m. self might not exist in the graph. Terraform's own depends_on docs acknowledge the wider point: some dependencies are hidden and can't be inferred from configuration.

→ Trace a resource back to its file, module and revision with IaC Explorer

Terraform visualization tools compared

You don't have to hand-roll everything. Here's an honest look at the common options. Check each project's recent activity before standardizing on it:

ToolInputGood forWatch out for
terraform graph and GraphvizYour configurationExact ordering, debugging cyclesNoisy, no boundaries or flows
Rover (open source)Config and plan, or plan JSONInteractive local exploration, SVG exportRuns init and plan by default, so it needs the same access and variables
InfraMap (open source)State or HCLSimplified graphs, with provider logic for AWS, Google Cloud, Azure, OpenStack and FlexibleEngineOther providers get all resources with no simplification
Terraform Module VisualizerPasted HCLQuick inventory, no installText scan, not a resolved dependency graph
Architecto IaC featuresConnected repos and importsKeeping module, resource and architecture context togetherBigger setup than a one-off command

Our take: use the CLI to debug, a local viewer to explore, and a proper diagram to communicate. Trouble starts when one artifact tries to do all three. If you're weighing code-generated pictures against hand-drawn ones, see architecture diagram as code vs drag and drop.

→ Compare Architecto and Cloudcraft for infrastructure diagrams

Generate an architecture diagram from Terraform code

Want to visualize Terraform infrastructure as a diagram people will actually use? Generated output is your inventory, not your finished picture. Five steps get you from one to the other.

  1. Pick one root module and one environment. A diagram of "all our Terraform" answers nothing. Name the workspace in the caption.
  2. Collapse resources into concepts. A load balancer, listener and target group become one "Load balancer" box. Good module boundaries make this much easier.
  3. Draw boundaries. Add accounts, networks, tiers and trust zones. The graph won't draw these for you.
  4. Replace dependency arrows with flows. Redraw every line as "who calls whom", then add the protocol and port. Use the security group rules as evidence.
  5. Add what Terraform doesn't know. Include users, third-party APIs, manually created resources and anything owned by another team.

Before you publish it, run this checklist:

  • Caption names the workspace, environment and commit
  • Every arrow means traffic or data flow, not build order
  • Public, private and external zones are visible
  • Every data store has a labelled path to its callers
  • External dependencies are on the page
  • Unmanaged resources are marked as unmanaged
  • A named owner will update it when the code changes

Inherited the whole repo rather than one module? Our guide to reverse engineering architecture from code walks through the wider process.

→ Turn your inventory into an editable first draft with Architect AI

Keep your Terraform diagram honest as things change

A diagram generated from code can still be wrong if someone clicked around in the console last Tuesday. Your config, state and real infrastructure can all disagree.

The check is built in. A refresh-only plan compares each resource against real infrastructure and reports the differences without changing anything:

terraform plan -refresh-only -detailed-exitcode

Per the plan docs, exit code 0 means no changes, 1 means an error and 2 means changes were found. That makes it easy to schedule. If you have plan JSON, resource_drift holds the differences Terraform found between the prior saved state and the latest one.

The drift control explainer covers the wider process. One limit to remember: this only checks what Terraform already tracks. A database someone created by hand won't appear, because it was never in state.

→ Compare architecture intent with deployed reality using Drift Detector

Key takeaways

  • terraform graph shows dependency ordering. Treat every arrow as "depends on", never as traffic.
  • tred and a left-to-right layout make the output far easier to read.
  • Use state for "what do we manage?", plan JSON for "what's changing?" and refresh-only plans for "what drifted?".
  • Your most important runtime dependency may not exist in the graph at all.
  • Generated output is the inventory. Boundaries, flows and external systems are the architecture.
  • Plan files and JSON output can expose sensitive values, so handle them like secrets.

→ Run your diagram past the Architecture Review Checklist Builder

FAQ

How do I visualize a Terraform graph?

Run terraform init, then pipe terraform graph into Graphviz with terraform graph | dot -Tsvg > graph.svg. The command prints DOT text, not an image, so Graphviz does the rendering. Add tred before dot to remove redundant edges on larger configurations.

Can I generate an architecture diagram from Terraform code?

Partly. Terraform can give you resources, modules and dependency order, but an architecture diagram also needs traffic flows, trust boundaries and systems Terraform doesn't manage. Use the code as the inventory, then add those layers yourself or in a tool that keeps the code as context.

How do I visualize Terraform state?

Use terraform state list to see managed resources, filtered by module when needed, and terraform show -json to get the state as JSON for scripts or a third-party viewer. State shows what Terraform last recorded, so run terraform plan -refresh-only if you need to check it against real infrastructure.

What is the difference between terraform graph and terraform plan?

terraform graph shows dependency ordering, while terraform plan shows the actions needed to reach your configuration. You can combine them: terraform plan -out=tfplan followed by terraform graph -plan=tfplan draws the graph for applying that specific plan.

Is it safe to share Terraform plan JSON with a visualization tool?

Treat it as sensitive. Terraform's docs warn that sensitive data is saved in cleartext in plan files, and that terraform show -json displays sensitive state values in plain text. Review where the file goes before uploading it anywhere or storing it as a CI artifact.

→ Keep Terraform and architecture in one place with IaC Orchestration

Stop shipping spaghetti to your design review

terraform graph is a great debugger and a terrible architecture diagram. Respect both facts and you'll stop losing afternoons to DOT files.

Start small: render the graph, clean it up, then spend your time on what the machine can't infer, like flows, boundaries and the stuff Terraform has never heard of. Architecto gives that diagram a home next to your infrastructure code.

→ Start free and map your Terraform with Architecto

常见问题

读者在实践本页内容前会提出的问题。

How do I visualize a Terraform graph?

Run terraform init, then pipe terraform graph into Graphviz with terraform graph | dot -Tsvg > graph.svg. The command prints DOT text, not an image, so Graphviz does the rendering. Add tred before dot to remove redundant edges on larger configurations.

Can I generate an architecture diagram from Terraform code?

Partly. Terraform can give you resources, modules and dependency order, but an architecture diagram also needs traffic flows, trust boundaries and systems Terraform doesn't manage. Use the code as the inventory, then add those layers yourself or in a tool that keeps the code as context.

How do I visualize Terraform state?

Use terraform state list to see managed resources, filtered by module when needed, and terraform show -json to get the state as JSON for scripts or a third-party viewer. State shows what Terraform last recorded, so run terraform plan -refresh-only if you need to check it against real infrastructure.

What is the difference between terraform graph and terraform plan?

terraform graph shows dependency ordering, while terraform plan shows the actions needed to reach your configuration. You can combine them: terraform plan -out=tfplan followed by terraform graph -plan=tfplan draws the graph for applying that specific plan.

Is it safe to share Terraform plan JSON with a visualization tool?

Treat it as sensitive. Terraform's docs warn that sensitive data is saved in cleartext in plan files, and that terraform show -json displays sensitive state values in plain text. Review where the file goes before uploading it anywhere or storing it as a CI artifact.

相关阅读

继续推进架构工作流。

Terraform Graph Visualization: From Spaghetti to Diagram | Architecto