Terragrunt vs Terraform ā When to Use Which in 2026
Terragrunt wraps Terraform to solve problems like DRY configs, remote state management, and multi-environment setups. Here's when you actually need it and when you don't.
Terragrunt is a thin wrapper around Terraform that solves specific problems Terraform doesn't handle well out of the box. You don't always need it ā but when you do, it saves hours of config duplication.
What Terraform Doesn't Solve Well
Problem 1: Remote state configuration repeated everywhere
In plain Terraform, every module needs its own backend config:
# You write this in every module:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "production/vpc/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}30 modules = 30 copies of this. Change the bucket name? Update 30 files.
Problem 2: DRY configuration across environments
dev, staging, prod often have identical structure with different values. Plain Terraform forces you to either duplicate code or build complex module hierarchies.
Problem 3: Dependency ordering across modules
Running terraform apply in the right order across multiple modules is manual. Forget the order = broken infra.
What Terragrunt Adds
1. DRY remote state ā one root config, all modules inherit:
# terragrunt.hcl (root)
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}Every module that includes this root config automatically gets the right state path. Change bucket once, applies everywhere.
2. DRY configurations with include:
# modules/vpc/terragrunt.hcl
include "root" {
path = find_in_parent_folders()
}
inputs = {
vpc_cidr = "10.0.0.0/16"
name = "production-vpc"
}No backend configuration needed ā inherited from root.
3. Module dependencies:
# modules/eks/terragrunt.hcl
dependency "vpc" {
config_path = "../vpc"
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
subnet_ids = dependency.vpc.outputs.private_subnet_ids
}Run terragrunt run-all apply ā Terragrunt figures out the dependency graph and applies in the right order automatically.
Typical Terragrunt Directory Structure
infrastructure/
āāā terragrunt.hcl # Root config ā remote state, common vars
āāā production/
ā āāā account.hcl # AWS account ID, region
ā āāā vpc/
ā ā āāā terragrunt.hcl # VPC inputs
ā āāā eks/
ā ā āāā terragrunt.hcl # EKS inputs, depends on vpc
ā āāā rds/
ā āāā terragrunt.hcl # RDS inputs, depends on vpc
āāā staging/
āāā account.hcl
āāā vpc/
ā āāā terragrunt.hcl # Same structure, different values
āāā eks/
ā āāā terragrunt.hcl
āāā rds/
āāā terragrunt.hcl
# Apply everything in production in dependency order:
cd production && terragrunt run-all apply
# Apply just one module:
cd production/eks && terragrunt apply
# Plan everything:
terragrunt run-all planTerragrunt vs Terraform Workspaces
Many teams use Terraform workspaces for multi-environment. Terragrunt and workspaces solve the same problem differently:
| Terraform Workspaces | Terragrunt | |
|---|---|---|
| State separation | Per-workspace state file | Per-directory state file |
| Config separation | Same .tf files, terraform.workspace variable | Separate terragrunt.hcl per env |
| Visibility | Easy to accidentally apply to wrong workspace | Clear directory structure |
| Complexity | Lower | Higher |
| DRY remote state | No | Yes |
| Module dependencies | Manual | Automatic |
Rule of thumb: Workspaces work fine for 2-3 environments with simple infra. Terragrunt pays off when you have 4+ environments or 10+ modules that depend on each other.
When You Don't Need Terragrunt
- Single environment or simple infrastructure
- Small team (1-3 people) where duplication is manageable
- You already have good workspace + module structure
- You're just getting started with Terraform
Terragrunt adds complexity. Don't introduce it until you feel the pain it solves.
When You Do Need Terragrunt
- Multiple environments (dev/staging/prod/DR) with identical structure
- Many modules that depend on each other
- Remote state config is being duplicated across modules
- You want
run-allto apply your entire infrastructure in one command
Terragrunt with OpenTofu
Terragrunt works with OpenTofu (the open-source Terraform fork) too:
# Use OpenTofu instead of Terraform
export TERRAGRUNT_TFPATH=tofu
terragrunt applyLearn Terraform and infrastructure management deeply at KodeKloud.
Today I Fixed
Short real fixes from production ā posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam ā just practical engineering content.
Related Articles
What is Infrastructure as Code? Explained Simply (2026)
Infrastructure as Code (IaC) explained in plain English ā what it is, why every DevOps team uses it, and how to get started with Terraform and Pulumi in 2026.
How to Use AI Agents to Automate Terraform Infrastructure Changes in 2026
AI agents can now plan, review, and apply Terraform changes from natural language. Here's how agentic AI is transforming infrastructure-as-code workflows.
AI Agents for Automated Terraform Code Review ā The Future of IaC Quality
How AI agents are automating Terraform code review with security scanning, cost estimation, best practice enforcement, and drift prevention. Covers practical tools, custom LLM pipelines, and CI/CD integration.