DEV Community

Amaresh Pelleti
Amaresh Pelleti

Posted on Originally published at devtoolhub.com

Terragrunt vs Terraform: What's Actually Different

Originally published on DevToolHub.

Terragrunt isn't a Terraform competitor. It's a thin wrapper that runs on top of OpenTofu or Terraform, and the confusion about what it actually adds is real enough that "terragrunt vs terraform workspaces" and "terragrunt vs terraform modules" are both real searches. Here's what Terragrunt actually does, verified against its current docs and a real CLI run — including one command-syntax change that will break a tutorial written more than a year ago.

Terragrunt vs Terraform: What Terragrunt Actually Adds

Per Terragrunt's own overview, its job is solving code duplication across multiple environments and regions. A team running the same infrastructure in dev, staging, and prod normally either copies the same .tf files three times or reaches for workspaces. Terragrunt's answer is four features:

  • DRY configuration. An include block lets every environment inherit shared provider and backend settings from one root config, instead of repeating them.
  • Remote state generation. A remote_state block auto-generates the backend.tf file before every run, so nobody hand-writes backend config per environment.
  • Module dependencies. A dependency block lets one unit read another unit's outputs — Terragrunt runs terragrunt output on the dependency first, then feeds those values in.
  • Dependency-ordered run --all. Terragrunt builds a directed acyclic graph from your dependency blocks and runs commands across every unit in the correct order automatically.

None of this replaces OpenTofu or Terraform. Terragrunt still shells out to one of them for every actual plan/apply — it's an orchestration layer, not a second IaC engine.

The Command That Changed: run-all Is Gone

If you learned Terragrunt from an older tutorial, this will break on you. Terragrunt went through a CLI redesign that folded the old run-all and graph commands into a single run command with flags. We tested this directly on Terragrunt 1.1.6:

$ terragrunt run --all plan --non-interactive
INFO  The following units will be run, starting with dependencies and then their dependents:
.
╰── .
[.] tofu: No changes. Your infrastructure matches the configuration.

❯❯ Run Summary  1 units  564ms
   Succeeded    1
Enter fullscreen mode Exit fullscreen mode
$ terragrunt run-all plan --non-interactive
ERROR unknown command: "run-all". Terragrunt no longer forwards unknown commands by
default. Use 'terragrunt run -- run-all ...' or a supported shortcut.
Enter fullscreen mode Exit fullscreen mode

That's not a deprecation warning — on a current install, the old syntax is a hard error. The fix is mechanical: terragrunt run-all apply becomes terragrunt run --all apply, and every other run-all <command> invocation follows the same pattern.

Terragrunt vs Terraform vs OpenTofu: Which Engine Runs

Terragrunt doesn't force a choice between OpenTofu and Terraform. Per its engine documentation, without the experimental Engine feature enabled, "Terragrunt will determine how IaC updates will be performed by doing things like invoking the tofu/terraform binary directly" — it uses whichever binary it finds. We confirmed this: with only tofu installed and no terraform binary on the test machine, terragrunt init correctly invoked tofu for every step, and Terragrunt's own --help output labels its command shortcuts "OpenTofu shortcuts" first.

If you need to pin a specific engine explicitly rather than relying on autodetection, that's what the experimental engine block is for:

# requires: export TG_EXPERIMENTAL_ENGINE=1
engine {
  source  = "github.com/gruntwork-io/terragrunt-engine-opentofu"
  version = "v0.1.0"
}
Enter fullscreen mode Exit fullscreen mode

For most setups, autodetection is enough — install whichever binary you want (tofu or terraform), and Terragrunt uses it without extra configuration.

A Minimal DRY Setup

This is the actual pattern the DRY features exist for — one root config, environment-specific units that inherit from it:

infra/
├── terragrunt.hcl          # root: shared provider + remote_state config
├── dev/
│   └── terragrunt.hcl      # include { path = find_in_parent_folders() }
├── staging/
│   └── terragrunt.hcl
└── prod/
    └── terragrunt.hcl
Enter fullscreen mode Exit fullscreen mode

Each environment's terragrunt.hcl is a few lines — an include block plus whatever's actually different about that environment (instance size, region, a different dependency output). The provider block, backend config, and remote state setup live once, in the root file.

What Terragrunt Doesn't Solve

Terragrunt adds a real dependency to your toolchain and a second config language layer (HCL generating HCL) on top of the one you already have. Two things worth knowing before adopting it:

  • It's still Gruntwork's tool. Per its docs, Terragrunt is maintained by Gruntwork, not a vendor-neutral foundation the way OpenTofu is under the Linux Foundation. That's not a red flag — it's a mature, 9.9k-star project with paid enterprise support available — but it's a different governance model than the engine it wraps.
  • The Engine feature (explicit OpenTofu/Terraform pinning) is still experimental, gated behind TG_EXPERIMENTAL_ENGINE=1. Autodetection covers the common case; don't build a workflow around the pinning syntax expecting it to be stable yet.

If your actual problem is "I have one root module and want per-environment variable values," Terraform/OpenTofu's built-in .tfvars files or workspaces solve that without adding a new tool. Terragrunt earns its place once you have multiple modules with real dependencies between them, or enough environments that copy-pasted backend blocks have become their own maintenance problem.

If you haven't settled the engine question yet, our OpenTofu vs Terraform guide covers licensing and compatibility in more depth — Terragrunt works the same way on top of either. If you're documenting whichever module structure you land on, our terraform-docs GitHub Action guide covers keeping that in sync in CI, and our Terraform Helm provider migration guide covers a real breaking-change migration if Helm is part of your stack.

Frequently Asked Questions

Q: Is Terragrunt a replacement for Terraform or OpenTofu?
A: No. Terragrunt is an orchestration wrapper — it still invokes the tofu or terraform binary for every actual infrastructure change. It doesn't have its own execution engine outside the experimental Engine feature.

Q: Does terragrunt run-all still work?
A: No, not on current versions. We tested it directly on Terragrunt 1.1.6 and got ERROR unknown command: "run-all". Use terragrunt run --all <command> instead — the CLI redesign folded run-all into run as a flag.

Q: Terragrunt vs Terraform workspaces — what's the actual difference?
A: Workspaces let one set of .tf files manage multiple named state instances from the same config. Terragrunt instead uses separate directories (units) per environment, each with its own remote_state block and its own real backend, inheriting shared settings via include. Workspaces are simpler for small setups; Terragrunt's directory-per-environment model scales better once environments need genuinely different configuration, not just different variable values.

Q: Does Terragrunt work with OpenTofu?
A: Yes, and its CLI help labels the primary command shortcuts "OpenTofu shortcuts." Without the experimental Engine feature, Terragrunt auto-detects and invokes whichever of tofu or terraform is on your system PATH.

Q: Do I need Terragrunt if I'm already using OpenTofu?
A: Only if you're managing multiple environments or modules with real dependencies between them. OpenTofu alone is enough for a single module with .tfvars-based environment differences.

Quick Summary:

  • Terragrunt is an orchestration wrapper, not an alternative to OpenTofu/Terraform — it still shells out to one of them for every actual change
  • Core features: DRY config via include, auto-generated remote state, dependency blocks for cross-module outputs, and dependency-ordered run --all
  • terragrunt run-all is gone on current versions — confirmed via direct test, it's now a hard error, not a warning. Use terragrunt run --all <command>
  • Terragrunt auto-detects tofu or terraform on PATH; explicit engine pinning is still an experimental feature
  • Worth adopting once you have multiple environments or modules with real dependencies; skip it for a single module that just needs different variable values

Check docs.terragrunt.com before pinning a Terragrunt version in CI — the CLI redesign is still an active migration, and more run-all-style syntax changes could land before it's fully settled.

Top comments (0)