Skip to main content
Cloud DevOps Solutions
Get a quote Talk to an engineer

Infrastructure as code

Terragrunt Consulting for Multi-Account Terraform and OpenTofu Estates

Terragrunt is a thin wrapper around Terraform and OpenTofu that reduces repetition across environments by generating backend and provider configuration, managing dependencies between stacks and running commands across many of them. We introduce it only where repetition hurts, and design the layout, pipeline and exit path.

Key takeaways

  • Terragrunt solves repetition and orchestration across many Terraform stacks, not Terraform's core limitations.
  • It adds a second configuration layer, so it earns its place only once you have many environments or accounts.
  • A clean directory layout and a small set of shared includes matter more than clever features.
  • Dependency handling and run-all commands are powerful but need guardrails in production.
  • Teams with a few stacks usually do better with plain Terraform modules.

What teams use Terragrunt for

Many accounts and regions

Identical stacks deployed across dozens of AWS accounts or Azure subscriptions without copying backend blocks.

Generated remote state configuration

Backend settings and keys derived from the directory path, removing hand-edited state keys.

Ordered multi-stack applies

Network, then data, then application stacks, with outputs passed between them through declared dependencies.

Environment promotion

The same module version promoted from development to staging to production by changing one reference.

Consistent provider and tagging setup

Provider blocks and default tags generated once and applied everywhere.

What Terragrunt is, and the problem it solves

Terraform is good at describing one stack. It is less comfortable when you have forty of them: a development, staging and production environment, across several accounts and regions, each needing the same backend settings, the same provider configuration and a particular order of deployment. Copy and paste works for a while, then someone forgets to change a state key and two environments share state.

Terragrunt is a thin wrapper that addresses exactly that. It reads small configuration files, generates the repetitive Terraform blocks, wires dependencies between stacks and runs Terraform or OpenTofu on your behalf. It does not change how Terraform plans or applies. Think of it as orchestration and templating around the tool, rather than a replacement for Terraform.

We use it where the scale justifies it, and we say so when it does not. Our broader Terraform infrastructure as code service covers the foundations that Terragrunt depends on.

How we lay out a Terragrunt repository

A clear layout is the whole game. We usually organise directories as account, then region, then stack, with shared configuration near the root:

# live/prod/eu-west-1/network/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "git::https://github.com/example-org/infra-modules.git//network?ref=v1.4.0"
}

inputs = {
  cidr_block  = "10.20.0.0/16"
  environment = "prod"
}

The root file defines the remote state backend using the directory path to derive each key, so no one hand-writes a state location. The leaf file names a module version and passes inputs. Promotion between environments becomes a pull request that changes the version reference.

Versioned modules

Source modules live in their own repository and are pinned to a tag. This keeps infrastructure code and environment configuration separate, and means a module change reaches production only when someone updates a version number. The practice mirrors our guidance on module versioning and registries.

Shared includes, used sparingly

It is tempting to put everything in includes and generate half the repository. Resist that. Include what is genuinely identical everywhere: backend, provider, required versions and default tags. Anything environment-specific stays in leaf files so a reader can understand a stack by opening one directory.

Dependencies and ordering

Terragrunt lets a stack declare that it needs outputs from another, such as a database stack reading subnet identifiers from the network stack. It also derives an apply order from those declarations. Two details matter in practice.

First, mock outputs let a plan run before a dependency exists, which is useful on first deployment but dangerous if mocks leak into a real apply. We restrict mock use to specific commands.

Second, dependency graphs can hide coupling. If every stack depends on five others, a small change ripples widely. We keep the graph shallow and prefer data sources or well-known parameter names for loose coupling where it makes sense.

Pipelines and run-all

The run-all family of commands applies an operation across many stacks. It is convenient and also the fastest way to change a lot of production at once. Our pipelines detect which directories changed in a pull request, plan only those and their dependents, post the results for review, and apply from a controlled runner under approval. We cap parallelism so provider rate limits and lock contention do not cause failures. Pull requests link back to the plan so that approvers read what will change.

Security and access

Everything from Terraform applies here: short-lived federated pipeline credentials, separate plan and apply roles, encrypted and versioned state with narrow access, and static analysis such as Checkov in CI. Terragrunt adds one specific concern: generated files and before_hook or after_hook commands can execute arbitrary scripts, so we review hooks like any code that runs with deployment privileges and avoid them where a pipeline step would do. Pin the Terragrunt version along with Terraform or OpenTofu so everyone, including CI, runs the same binaries.

Cost and capacity

Terragrunt is free and open source. The real cost is another layer to learn and maintain, plus extra care with onboarding. Plan speed is dominated by Terraform, provider API calls and state size, so keeping stacks small helps more than any wrapper feature. We do not quote performance numbers; they depend on your providers and accounts.

Day-2 operations

Upgrades involve three moving parts: Terragrunt, the Terraform or OpenTofu binary and the providers. We pin all three, upgrade in a lower environment and read changelogs for configuration changes, since the wrapper’s configuration syntax has evolved over time. Drift checks run as scheduled plans per stack, as described in our drift detection guide. For multi-environment structure more generally, see Terraform multi-environment setup.

Common failure modes

  • Adopting it too early. Three stacks do not need a wrapper.
  • Over-generated configuration. Nobody can tell what a stack contains without running the tool.
  • Deep dependency chains. Slow applies and fragile ordering.
  • Unreviewed run-all. A broad command changes many environments together.
  • Unpinned tooling. Engineers and CI on different versions produce different results.

When Terragrunt is the wrong choice

If you have a small number of stacks, use plain modules and a pipeline. If your pain is code review and locking rather than repetition, tools such as Atlantis address that more directly. If you want loops and abstraction in a real language, Pulumi is a different route altogether. And if you are AWS-only and prefer a native service, CloudFormation with StackSets covers multi-account rollout without any wrapper.

Terragrunt works with both Terraform and OpenTofu, so it does not force the licensing decision. If you are unsure whether it suits your estate, talk to us and we will look at your stack count and layout before recommending anything.

Official documentation: terragrunt.gruntwork.io

How we work with Terragrunt

  1. 01

    Decide whether you need it

    We count your stacks and environments and test whether plain modules and a pipeline already solve the repetition.

  2. 02

    Design the directory layout

    A hierarchy of account, region and stack, with shared root configuration at the top and thin leaf files.

  3. 03

    Centralise common settings

    Backend, provider, tagging and version constraints go into shared includes that leaf stacks inherit.

  4. 04

    Model dependencies

    Stacks declare what they need from others, with sensible mock outputs for planning before dependencies exist.

  5. 05

    Build the CI workflow

    Pipelines detect changed stacks, run plans in order and apply from a controlled runner with limited blast radius.

  6. 06

    Document and keep an exit path

    Conventions are written down, and the layout stays simple enough that you could return to plain Terraform.

Terragrunt compared with the alternatives

We recommend the tool that fits your team, not the one we know best. Here is when each option makes sense.

OptionChoose it when
TerragruntTerragrunt is a thin wrapper around Terraform and OpenTofu that reduces repetition across environments by generating backend and provider configuration, managing dependencies between stacks and running commands across many of them.
Plain Terraform modulesChoose them when you have a handful of stacks. A module per pattern and a root per environment is simpler and has no extra tool.
Terraform workspacesChoose them cautiously for near-identical short-lived environments. They share a backend and are easy to apply to the wrong target.
Atlantis or Terraform Cloud style automationChoose these if the real pain is pull request workflow and locking rather than repetition in configuration.
PulumiChoose it if you want loops and abstractions in a general-purpose language rather than a wrapper around HCL.

Tools we use alongside Terragrunt

TerraformOpenTofuAtlantisGruntwork modulesCheckovTFLintInfracostGitHub ActionsGitLab CI/CDAWS S3Azure Blob StorageOpen Policy Agent

Frequently asked questions

What is Terragrunt used for?
Terragrunt is used to keep Terraform and OpenTofu configuration DRY across many environments. It generates backend and provider blocks, passes outputs between stacks through declared dependencies, and runs commands over groups of stacks. It does not replace Terraform; it calls it.
Do I need Terragrunt?
Probably not if you have a few environments. Plain modules plus a good pipeline cover most small estates. It starts to pay off with many accounts, regions or stacks where copied backend blocks and manual ordering cause mistakes. We assess this honestly before introducing it.
Terragrunt or Terraform workspaces?
Terragrunt gives each stack its own state and configuration through directories, which makes targets explicit. Workspaces share one backend and configuration, so a wrong workspace selection can change the wrong environment. For production separation we generally favour directories, whichever tool generates them.
Does Terragrunt work with OpenTofu?
Yes. Terragrunt can drive either Terraform or OpenTofu through its configuration. The choice of binary is separate from the wrapper, which makes it useful if you are evaluating OpenTofu. We test your providers and modules with both before you commit.
Is run-all safe in production?
Only with care. Running a command across every stack can apply many changes at once. We scope it to specific directories, require reviewed plans, limit parallelism and keep production applies to a pipeline with approval, rather than allowing broad runs from a laptop.
Can we remove Terragrunt later?
Yes, if the layout is kept simple. The underlying Terraform modules and state remain valid, so you would replace generated blocks with explicit ones and wire ordering into your pipeline. We design with that exit in mind so you never feel locked in.

Talk to an engineer about Terragrunt

Book a free 30-minute call. We review your current setup and tell you honestly whether and how we can help.

Written by Saddique Khan, DevOps / SRE / Cloud Consultant Engineer. Last updated 2026-10-09.