Running Terraform Only Where It Matters: Terramate Change Detection with terramate run --changed
Use Terramate's Git-based change detection to plan and apply only the Terraform stacks affected by a change, with dependency-ordered execution, verification steps, and recovery guidance.
22 May 2026, 23:17 UTC

The problem: full-repo plans that waste CI time
Once a Terraform repository grows past a handful of root modules, running terraform plan everywhere on every pull request becomes the bottleneck. Most changes touch one or two stacks, yet CI pays the cost of planning all of them—and a failure in an unrelated stack can block your change.
Terramate's change detection addresses this directly. It compares your working tree against a Git ref (typically the base branch, such as origin/main) and runs commands only in stacks—Terramate's unit of Terraform configuration, usually a directory marked by a stack.tm.hcl file—that changed or depend on something that changed. The result: shorter pipelines, smaller blast radius, and applies that still respect dependency order.
Prerequisites
- A Git repository with enough history to resolve the base ref. Change detection is Git-based; a shallow CI clone that lacks the base commit will misreport or fail.
- Terramate installed (a single binary). Confirm with
terramate version. - Terraform installed and each stack already initializable (backend config and providers resolvable).
- Stacks defined. A minimal stack marker is a
stack.tm.hclcontaining astack {}block in each Terraform root directory you want orchestrated.
Flag names and configuration syntax have evolved across Terramate releases. Before relying on anything below, run terramate run --help and terramate list --help on your installed version and adjust accordingly.
Step 1: Preview which stacks are affected
From the repository root, in any shell with the repo checked out (no special permissions needed—read-only operation):
terramate list --changedThis prints the stack paths Terramate considers changed relative to the default base ref. Run this before anything else. If the list doesn't match the files you edited, stop and investigate your Git state—common causes are uncommitted changes you expected to be ignored, a missing base ref, or a shallow clone. To compare against an explicit ref, check your version's help for the flag that sets the change base (for example, a --git-change-base-style option).
Step 2: Plan only the changed stacks
terramate run --changed -- terraform init -upgrade
terramate run --changed -- terraform plan -out=tfplanEverything after -- is executed in each changed stack's directory. Terramate orders execution using dependencies declared in stack configuration (after/before blocks) and output wiring, so an upstream network stack plans before a downstream app stack that consumes its outputs—not in lexicographic order.
Expected check: the command output shows plan activity only in the stacks from step 1, and upstream stacks appear before their dependents.
Step 3: Apply after review
terramate run --changed -- terraform apply tfplanRun this only after the plans have been reviewed (in CI, typically on merge to the main branch). Because execution is dependency-ordered, an upstream apply completes before downstream applies start. If any stack fails, Terramate halts execution of stacks that depend on it, which limits partial-rollout damage.
Verifying the behavior before you trust it
- Create a scratch repo with two stacks, make one depend on the other via
after, commit, then edit a file in only one stack. - Run
terramate list --changedand confirm only the edited stack (and anything depending on it) is listed. - Run
terramate run --changed -- terraform planand confirm no plan output appears for untouched stacks. - In CI, confirm the checkout fetches enough history for the base ref to resolve—for example, a full fetch or a fetch depth that includes the merge base with the base branch.
Recovery when a stack fails mid-run
A failed apply leaves that stack's Terraform state exactly as terraform apply left it—Terramate adds orchestration, not a new state model. Recovery is therefore ordinary Terraform recovery, scoped correctly:
- Fix the offending configuration in the failed stack.
- Retry just that stack by targeting its path, e.g.
terramate run -C path/to/stack -- terraform apply(confirm the exact targeting flag interramate run --helpfor your version), or re-run the same--changedcommand—the stack is still changed relative to the base ref until the branch merges. - Re-run dependents afterward if their plans referenced outputs that changed.
Limitations to keep in mind
- Change detection is only as accurate as your Git state. Uncommitted files, incorrect base refs, and shallow clones are the top causes of surprising stack lists.
- Parallel execution flags can speed up large runs, but parallelism can violate implicit constraints—shared backends, provider rate limits, or resources two stacks touch without declaring a dependency. Declare real dependencies explicitly rather than relying on run order.
- Changes to shared modules should mark dependent stacks as changed, but verify this in your setup with the scratch-repo test above before trusting it in production pipelines.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.