Terragrunt
By Gruntwork
Terragrunt is a thin wrapper around Terraform that adds conventions for keeping infrastructure-as-code configurations DRY across multiple environments and modules. It manages remote state configuration, provider blocks, and variable…
Definition
Terragrunt is a thin wrapper around Terraform that adds conventions for keeping infrastructure-as-code configurations DRY across multiple environments and modules. It manages remote state configuration, provider blocks, and variable inheritance so that teams do not have to copy and paste the same Terraform boilerplate into every environment directory. Terragrunt calls the Terraform binary under the hood, adding a layer of orchestration for dependency ordering, run-all commands, and hierarchical configuration merging.
Overview
Terraform on its own encourages a repository layout where each environment or region gets its own directory with a full copy of provider, backend, and variable declarations. As an organization's infrastructure grows, this pattern produces duplicated HCL that must be updated in lockstep everywhere, which is error-prone and slow to review. Terragrunt was built by Gruntwork to solve this specific pain point by introducing a `terragrunt.hcl` file that sits alongside or instead of duplicated Terraform code, letting teams define shared configuration once and inherit it down a directory tree. Mechanically, Terragrunt reads its own configuration file, resolves inheritance from parent `terragrunt.hcl` files, generates the appropriate backend and provider blocks, and then invokes the real `terraform` binary with the assembled configuration and working directory. It supports `dependency` blocks that let one module read outputs from another without manual wiring, and a `run-all` command that walks a directory tree and applies changes in the correct dependency order across many modules at once. Remote state configuration, such as an S3 bucket and DynamoDB lock table, can be declared once at the root and automatically applied to every child module. Terragrunt sits next to, not in competition with, tools like Terraform Cloud or Terraform's native workspaces. Workspaces solve a narrower problem of parameterizing a single module for multiple state files, whereas Terragrunt addresses cross-module orchestration and configuration reuse at a repository-wide scale. It differs from full platform-oriented tools such as Terraform Cloud or Spacelift in that it is a CLI-only, open-source layer with no hosted execution or web UI of its own; teams still need their own CI system or Terraform Cloud subscription to actually run Terragrunt commands in a pipeline. In practice, platform and DevOps teams adopt Terragrunt when they manage dozens of Terraform modules across many AWS accounts, regions, or environments and find that copy-pasted backend and provider blocks have become a maintenance burden. A typical setup places a root `terragrunt.hcl` with shared remote state and provider generation, and per-environment folders that reference shared modules with environment-specific inputs. Teams running `run-all plan` or `run-all apply` can preview or roll out changes across an entire environment in one command while Terragrunt resolves the dependency graph between modules. The trade-offs are real: Terragrunt adds another configuration language and another tool version to pin and troubleshoot, and its error messages are sometimes harder to interpret than raw Terraform's because failures can originate in the generation step rather than in Terraform itself. Teams with only a handful of environments or a single AWS account often find plain Terraform, workspaces, or a simple templating approach sufficient and skip Terragrunt entirely. It is best reached for once duplication in the Terraform codebase becomes measurable and painful, not as a default starting point for a new project.
Key Features
- Hierarchical `terragrunt.hcl` inheritance eliminates duplicated backend and provider blocks
- `run-all` command applies or plans changes across many modules in dependency order
- `dependency` blocks read another module's outputs without manual variable wiring
- Automatic generation of remote state and provider configuration for every child module
- Works transparently with any Terraform provider since it simply wraps the Terraform CLI
- Supports before/after/error hooks for running custom commands around Terraform operations
- Keeps environment-specific inputs isolated while sharing common module logic
- Compatible with existing Terraform modules without requiring them to be rewritten