Speed up Terraform CI/CD with Terramate’s Changed Detection
Learn how Terramate’s selective execution skips unchanged stacks in a monorepo, reducing plan/apply time and cost while keeping CI pipelines reliable.
03 Sept 2025, 09:30 UTC

The problem: wasted Terraform work in a monorepo
When a repository contains many Terraform stacks (e.g., networking, databases, services), a typical CI pipeline runs terraform plan or apply on every stack, even if only one folder changed. This adds minutes to each build, increases cloud‑provider API costs, and can mask real failures with noise from unrelated stacks.
Thesis: Terramate’s changed detection limits execution to stacks with actual file changes
Terramate stores, for each stack, the SHA of the files that were present at the last successful run. On the next invocation it compares that stored state with the current git diff. If a stack’s tracked files differ, Terramate marks the stack as “changed” and lets the wrapped Terraform command proceed; otherwise the stack is skipped.
How the feature works
terramate run --changed(or its alias--only-changed) triggers the detection logic.- A
.terramateignorefile works like.gitignore: patterns listed there are excluded from the change calculation, preventing irrelevant edits (e.g., documentation) from flagging a stack. - Before running Terraform, Terramate can also invoke
terramate generatelimited to the changed stacks, ensuring that any generated.tffiles are up‑to‑date.
Worked example: updating only the networking stack
Assume a repo layout:
repo/
stacks/
network/
main.tf
services/
main.tf
.terramateignore
The .terramateignore contains:
# Ignore docs and CI configs **/README.md **/.github/**
You make a change only in stacks/network/main.tf (e.g., add a new subnet). To verify that Terramate limits work:
- Ensure you have read access to the repository and the
terramatebinary is in yourPATH. - Run the detection command from the repo root:
# Run from the repository root terramate run --changed -- terraform plan -out=tfplan
Expected output (shortened):
[Terramate] Detected changes in stacks: network [Terramate] Skipping unchanged stacks: services # Terraform output for the network stack only ...
If you run the same command with no file changes, Terramate reports:
[Terramate] No changes detected. Skipping all stacks.
To confirm that .terramateignore works, edit a ignored file (e.g., README.md) and run the command again; you should see the “No changes detected” message, proving the ignore pattern prevented a false trigger.
Trade‑offs and limitations
- Dependence on a clean git history: Rebasing, squashing, or force‑pushes can alter the SHA that Terramate stored, causing it to either miss a real change or flag a stack incorrectly. Teams should avoid rewriting history on branches that Terramate relies on, or run
terramate run --reset-stateafter such operations. - Misconfigured ignore patterns: If
.terramateignore is too permissive, irrelevant edits (like a changed comment) will still mark a stack as changed, leading to unnecessary runs. Regularly review the file and test with the verification steps above. - Initial state: After cloning a fresh repo, Terramate has no stored state, so the first run treats every stack as changed. This is expected; subsequent runs benefit from the detection.
Actionable closing
To adopt changed detection in your CI pipeline:
- Add
terramate run --changed -- terraform apply -auto-approveas the step that applies infrastructure. - Cache the
.terramatedirectory (where Terramate stores state) between jobs to avoid resetting on every run. - Monitor pipeline logs for the “Detected changes in stacks” line; if you see many stacks listed unexpectedly, inspect
.terramateignoreand recent git history.
By letting Terramate decide which stacks truly need Terraform work, you cut down CI time, reduce cloud‑api spend, and keep feedback loops fast—without sacrificing the correctness of your monorepo deployments.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.