May 1, 2026 · Anton Grishko
Terragrunt 1.0 — what changed and why we bet on it
Terragrunt 1.0 stabilized the CLI surface, swapped command names, and added Stacks. Here's what we use, what we ignore, and what it means for IaC repos that already exist.
TL;DR — Terragrunt 1.0 froze the CLI, renamed
run-alltorun --all, shipped Stacks, and turned on a provider cache server by default. Migration is a one-linesed. We bumped two weeks after release and nobody noticed.
What 1.0 actually means
Terragrunt was already production-grade for years. The 1.0 stamp doesn't mark "now it's stable" — it marks "now the CLI surface is frozen." After this release, command names won't quietly shift between minor versions, and the wrappers that everyone (us included) built around terragrunt run-all apply won't break on next Tuesday's release. The reasons we ship Terragrunt at all are in Why we ship Terragrunt, not raw Terraform.
That's the headline. The interesting parts are underneath.
The CLI rename
The redesign migration guide covers the full surface. Short version:
Old:
terragrunt apply
terragrunt plan
terragrunt run-all apply
terragrunt run-all plan
New:
terragrunt run apply
terragrunt run plan
terragrunt run --all apply
terragrunt run --all plan
Two things to notice:
run-allis nowrun --all. A flag, not a separate command. Cleaner — there's one command that runs Terraform/OpenTofu, with a flag that decides whether to fan it out.- The old commands still work. There's a deprecation warning on stderr but no behavior change. You can migrate at your own pace.
For us this was a one-line sed on internal CI scripts, plus a memo to humans. Nothing exciting to write home about — which is exactly the right amount of excitement for a 1.0.
Stacks: the part most people will skip
terragrunt.stack.hcl lets you define a logical group of units and run them together — a cleaner replacement for the "directory-of-directories" pattern most of us use:
# live/prod/eks-cluster/terragrunt.stack.hcl
unit "vpc" {
source = "../../../modules/vpc"
}
unit "eks" {
source = "../../../modules/eks"
values = {
vpc_id = unit.vpc.outputs.vpc_id
}
}
unit "karpenter" {
source = "../../../modules/karpenter"
values = {
cluster_name = unit.eks.outputs.cluster_name
}
}
terragrunt run --all apply from that directory walks the graph in dependency order. Same as before, with cleaner syntax and an explicit values contract instead of dependency blocks scattered across files.
When does this earn its keep? When a stack is something you actually treat as a unit — a cluster, an environment, a tenant. When the units in a directory aren't conceptually related, plain dependency blocks are still fine.
We ship Stacks for new customer environments. Existing repos we migrated kept their dependency block layout — backwards compat is real, and rewriting working IaC for syntax is not a Q2 priority.
Provider cache server, on by default
This is the silent win. Terragrunt 1.0 runs a local provider cache server by default, sharing the OpenTofu/Terraform provider plugin binaries across every unit in a run --all.
Before: a 30-unit run-all apply would re-download the AWS provider 30 times. Or you'd manually configure TF_PLUGIN_CACHE_DIR and pray it was thread-safe (it isn't, fully).
After: provider downloads happen once per provider per host per run. On a fresh CI runner, our run --all apply runs got measurably faster — typically 30–50% on a 30-unit stack. On a warm runner, the gain is smaller but still positive because the cache server arbitrates concurrent reads cleanly.
Zero config to opt in. You're already opted in.
What stayed exactly the same
- HCL syntax — every existing config keeps working
include,dependency,generate,remote_state— unchangedterragrunt.hclunits (the directory-per-unit pattern) — unchanged, fully supported alongside Stacks- The way you read state — same backend, same files
This is the part that mattered for us. We migrate customer IaC repos onto Kuberly continuously, and a 1.0 release that broke dependency block semantics would have meant a quarter of pain. It didn't. Gruntwork held the line.
What we ignore
- The new
infocommand surface is fine, butterragrunt --helpis faster than learning a new subcommand - Stacks for trivial groups — if you have two units that share one dependency, the
dependencyblock is still simpler than aterragrunt.stack.hcl - Strict mode flags — useful for greenfield, noisy on existing repos. We turn them on per-environment as we tidy up
What this means for our customers
Every Kuberly stack ships as OpenTofu + Terragrunt straight to your Git repo. With 1.0, those repos are:
- Easier to onboard — the documented commands now match what's printed by
--help - Faster to apply — provider cache pays for itself on day one
- Less prone to "Terragrunt broke our CI on minor version bump" incidents
We bumped our default Terragrunt version on new environments two weeks after 1.0 shipped. Existing environments rolled in the next maintenance window. No customer noticed, which is the right outcome. That's the eject-friendly contract from You own the IaC. You own the infra doing its job.
Try it
If you're already running Terragrunt:
terragrunt --version
# bump in your CI image, deprecation warnings tell you exactly what to rename
terragrunt run --all plan
If you're shopping for a way to manage many OpenTofu modules: this is now the version to start on. Skip the pre-1.0 history.
Further reading
- Terragrunt 1.0 release notes — the official announcement.
- Terragrunt CLI redesign guide — what renamed and why.
- Stacks feature documentation — the new grouping primitive.
- OpenTofu provider installation docs — how the cache server works.
- HashiCorp Terraform language — the HCL surface Terragrunt wraps.
- Why we ship Terragrunt, not raw Terraform — the case for Terragrunt at scale.
- You own the IaC. You own the infra. — what shipping IaC into the customer's repo means.
Want Terragrunt 1.0 wired into your stack with zero migration drama? Talk to us.