Terramate Dependency Graph: Deterministic Module Ordering Explained
Terramate’s dependency graph automatically orders Terraform modules, ensuring deterministic applies. This guide shows how to declare dependencies, inspect the graph, and avoid common mistakes.
02 Jun 2026, 02:41 UTC

Why Terramate Needs a Dependency Graph
When a Terraform project grows beyond a single module, the order in which modules are applied becomes critical. A network module that creates a VPC must run before a subnet module that references that VPC. Terramate solves this by automatically building a directed acyclic graph (DAG) of all modules in the repository. The graph guarantees that tmt apply (or terraform apply invoked through Terramate) always follows a deterministic order that respects explicit depends_on relationships.
How the Graph Is Built
Each module contains a terramate.yaml file. The depends_on key lists other modules that must be applied first. Terramate walks the entire workspace, resolves all references, and constructs a DAG. If a cycle is detected, tmt init aborts with an error, preventing infinite loops.
Minimal Example
Consider a repository with two modules:
modules/vpcmodules/subnet
subnet module depends on the vpc module.
# modules/vpc/terramate.yaml
name: vpc
# No explicit dependencies – it is a root module.
# modules/subnet/terramate.yaml
name: subnet
depends_on:
- ../vpc
Run tmt init from the repository root. Terramate will:
- Validate that
../vpcexists. - Build a graph with a single edge
vpc → subnet. - Store the graph in
.tmt/graph.jsonfor later use.
Inspecting the Graph
The CLI exposes the graph in two useful formats:
tmt graph– a human‑readable tree.tmt graph --format dot– DOT syntax for Graphviz or other tools.
Example output of tmt graph:
vpc
└─ subnet
DOT output:
digraph terramate {
"vpc" -> "subnet";
}
Verify the edge direction matches the depends_on declaration. If the graph is empty or contains unexpected edges, revisit your terramate.yaml files.
Common Pitfalls and How to Avoid Them
| Issue | Why It Happens | Fix |
|---|---|---|
| Missing Module Reference | Path in depends_on points to a non‑existent module. |
Ensure the path is relative to the module’s parent directory and that the module contains a valid terramate.yaml. |
| Cycle Detection Failure | Indirect dependency loops (A → B → C → A). | Run tmt init – it will report the cycle. Remove or refactor the offending dependency. |
| Unnecessary Ordering Constraints | Declaring a dependency that is already implied by a parent module. | Remove redundant depends_on entries; the graph will infer the order from the module hierarchy. |
| Cross‑Workspace Dependency | Referencing a module that lives in a different Terramate workspace. | Either move the module into the current workspace or use Terramate’s workspace feature to declare cross‑workspace dependencies explicitly. |
Leveraging the Graph in CI/CD Pipelines
Many teams trigger tmt apply on every commit, which can be wasteful. With the graph, you can calculate the minimal set of modules that need re‑applying when a file changes:
# Example pseudo‑script in a CI job
changed_modules=$(git diff --name-only $BASE_SHA $HEAD_SHA | grep -o 'modules/[^/]*' | uniq)
for mod in $changed_modules; do
# Check if any downstream modules depend on $mod
downstream=$(tmt graph --format json | jq -r ".edges[] | select(.from==\"$mod\") | .to")
if [ -n "$downstream" ]; then
tmt apply $mod
fi
done
Replace the placeholder jq logic with your preferred JSON processor. The key takeaway: Terramate’s graph gives you a programmatic view of dependencies, making selective applies safe and efficient.
Version Assumptions and Verification Checklist
- Terramate version 0.15 or newer (the
depends_onkey andtmt graphcommand are stable in these releases). - All modules contain a
terramate.yamlwith anamefield. - Workspace root contains a
terramate.yamlthat definesmodulespaths. - Run
tmt initafter any change toterramate.yamlfiles to rebuild the graph. - Verify the graph with
tmt graph --format dotand open the DOT file in Graphviz or an online viewer.
Limitations
- The graph is static per run; dynamic runtime dependencies (e.g., modules created by Terraform modules themselves) are not represented.
- Terramate does not automatically merge graphs across workspaces; cross‑workspace dependencies must be expressed explicitly.
- Large graphs (hundreds of modules) may produce verbose DOT files; consider filtering or using the
--depthflag.
Conclusion
Terramate’s dependency graph turns a potentially chaotic Terraform deployment into a predictable, deterministic process. By declaring depends_on relationships, inspecting the graph, and integrating it into CI pipelines, you can avoid costly re‑applications and reduce deployment time. Remember to keep the graph acyclic, avoid redundant dependencies, and verify the graph after every change to your module structure.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.