CoursesInfrastructure as Code & automationIntermediate · Terraform at scale

Terragrunt: keeping it DRY

Wrap Terraform for many environments.

Intermediate10 min · lesson 12 of 23

As the directory-per-environment pattern grows, you notice new duplication: every environment’s config repeats the same backend block, the same provider setup, the same module calls with slightly different inputs. Terragrunt is a thin wrapper around Terraform whose whole purpose is to keep that DRY (Don’t Repeat Yourself). It lets you define the backend and common configuration once and inherit it everywhere, and call modules with per-environment inputs from small terragrunt.hcl files. It does not replace Terraform — it orchestrates it.

terragrunt.hcl (root + env)
# root terragrunt.hcl — define the backend ONCE for all environments
remote_state {
backend = "s3"
config = {
bucket = "acme-tfstate"
key = "${path_relative_to_include()}/terraform.tfstate" # auto per-dir key
encrypt = true
dynamodb_table = "tf-locks"
}
}
# environments/prod/network/terragrunt.hcl — tiny: include root + call the module
include "root" { path = find_in_parent_folders() }
terraform { source = "git::github.com/acme/modules.git//network?ref=v1.4.0" }
inputs = { cidr = "10.0.0.0/16", env = "prod" }

What Terragrunt removes

The repetition Terragrunt eliminates is real: the backend configuration (defined once, with the state key derived automatically from each directory’s path), the provider generation, and the boilerplate around calling modules. Each environment/component becomes a tiny terragrunt.hcl that includes the shared root and supplies only its inputs. It also adds conveniences like running Terraform across many modules with dependencies in the right order (run-all), which helps when a large estate is split into many small state files.

When to reach for it

Terragrunt earns its place when you have many environments and/or many small components (the split-state pattern), where the backend/boilerplate duplication and cross-module orchestration become painful. For a small project with one or two environments, plain Terraform with a directory per environment is simpler and Terragrunt is overhead. It is a "scale" tool: adopt it when the repetition it removes is actually hurting, not preemptively. Note some of its features (like generated backends) have since appeared in Terraform itself, so evaluate what you actually need.

Another tool is another thing to learn and secure
Terragrunt genuinely reduces duplication at scale, but it is a separate tool with its own syntax, versioning, and failure modes that everyone on the team must learn — so adopt it because the duplication is real, not because it is popular. Pin its version alongside Terraform’s, keep the wrapper thin (it should orchestrate, not hide, what Terraform is doing), and make sure the team can still reason about the underlying Terraform. A wrapper that obscures what is actually being applied to production is a liability, however DRY it makes the code.