Terragrunt wrapper for Terraform with DRY configurations. Enforces plan-before-apply workflow. Use when working with terragrunt.hcl files.
NEVER run without user confirmation:
terragrunt applyterragrunt destroyterragrunt run-all applyterragrunt run-all destroyALWAYS run first:
terragrunt planterragrunt validateāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā VALIDATE ā PLAN ā REVIEW ā APPLY ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
terragrunt validate
terragrunt hclfmt --check
# Single module
terragrunt plan
# All modules (be careful!)
terragrunt run-all plan
Show plan to user and wait for confirmation.
terragrunt apply
# Format check
terragrunt hclfmt --check
# Format and fix
terragrunt hclfmt
# Validate all
terragrunt run-all validate
infrastructure/
āāā terragrunt.hcl # Root config
āāā _envcommon/ # Shared configs
ā āāā vpc.hcl
āāā prod/
ā āāā env.hcl
ā āāā vpc/
ā ā āāā terragrunt.hcl
ā āāā eks/
ā āāā terragrunt.hcl
āāā staging/
ā āāā env.hcl
ā āāā vpc/
ā āāā terragrunt.hcl
āāā modules/ # Terraform modules
āāā vpc/
āāā main.tf
āāā variables.tf
āāā outputs.tf
# Root terragrunt.hcl
remote_state {
backend = "s3"
generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = var.aws_region
}
EOF
}
Terragrunt Checklist:
- [ ] terragrunt validate passed
- [ ] terragrunt hclfmt --check passed
- [ ] terragrunt plan reviewed
- [ ] Dependencies understood
- [ ] User confirmed changes
- [ ] Ready to apply
When using run-all:
--terragrunt-parallelism 1 for safer execution--terragrunt-exclude-dir for sensitive paths# Show dependency graph
terragrunt graph-dependencies
# Plan all with limited parallelism
terragrunt run-all plan --terragrunt-parallelism 1