Terragrunt Cheatsheet
Installation
| Platform | Command |
|---|
| macOS (Homebrew) | brew install terragrunt |
| Linux (Binary) | wget https://github.com/gruntwork-io/terragrunt/releases/download/v0.54.0/terragrunt_linux_amd64 && chmod +x terragrunt_linux_amd64 && sudo mv terragrunt_linux_amd64 /usr/local/bin/terragrunt |
| Windows (Chocolatey) | choco install terragrunt |
| Windows (Scoop) | scoop install terragrunt |
| Docker | docker pull alpine/terragrunt:latest |
| Version Manager (tgenv) | git clone https://github.com/cunymatthieu/tgenv.git ~/.tgenv && tgenv install latest |
| From Source (Go 1.21+) | git clone https://github.com/gruntwork-io/terragrunt.git && cd terragrunt && go install |
| Verify Installation | terragrunt --version |
Basic Commands
| Command | Description |
|---|
terragrunt init | Initialize Terraform with backend configuration automatically managed |
terragrunt plan | Generate and show execution plan for infrastructure changes |
terragrunt apply | Apply infrastructure changes (prompts for confirmation) |
terragrunt apply -auto-approve | Apply changes without interactive confirmation |
terragrunt destroy | Destroy all managed infrastructure resources |
terragrunt destroy -auto-approve | Destroy resources without confirmation prompt |
terragrunt validate | Validate Terragrunt and Terraform configuration syntax |
terragrunt fmt | Format Terraform configuration files to canonical style |
terragrunt fmt -recursive | Recursively format all .tf files in subdirectories |
terragrunt output | Display all output values from the state |
terragrunt output <name> | Display specific output value (e.g., terragrunt output vpc_id) |
terragrunt output -json | Display outputs in JSON format for parsing |
terragrunt show | Display current state or saved plan in human-readable format |
terragrunt console | Open interactive console for testing expressions |
terragrunt refresh | Update state file with real infrastructure status |
terragrunt state list | List all resources tracked in the state file |
terragrunt state show <resource> | Show detailed state information for specific resource |
terragrunt workspace list | List all available workspaces |
terragrunt workspace select <name> | Switch to specified workspace |
terragrunt workspace new <name> | Create and switch to new workspace |
Advanced Usage
| Command | Description |
|---|
terragrunt run-all plan | Execute plan across all modules in dependency order |
terragrunt run-all apply | Apply changes to all modules respecting dependencies |
terragrunt run-all destroy | Destroy all modules in reverse dependency order |
terragrunt run-all init | Initialize all modules in the directory tree |
terragrunt run-all validate | Validate all module configurations |
terragrunt run-all output | Display outputs from all modules |
terragrunt graph-dependencies | Generate and display module dependency graph |
terragrunt render-json | Render final configuration as JSON for inspection |
terragrunt hclfmt | Format terragrunt.hcl configuration files |
terragrunt state mv <source> <dest> | Move resource to different address in state |
terragrunt state rm <resource> | Remove resource from state without destroying it |
terragrunt import <address> <id> | Import existing infrastructure into Terraform state |
terragrunt taint <resource> | Mark resource for recreation on next apply |
terragrunt untaint <resource> | Remove taint marking from resource |
terragrunt plan -out=tfplan | Save execution plan to file for later apply |
terragrunt apply tfplan | Apply previously saved plan file |
terragrunt plan --terragrunt-log-level debug | Run plan with detailed debug logging |
terragrunt run-all apply --terragrunt-parallelism 3 | Limit parallel module execution to 3 concurrent operations |
terragrunt apply --terragrunt-source ../local-module | Override module source for local development/testing |
terragrunt run-all apply --terragrunt-include-dir vpc | Execute only on specific module directories |
terragrunt run-all apply --terragrunt-exclude-dir legacy | Exclude specific directories from execution |
terragrunt apply --terragrunt-include-external-dependencies | Include external dependencies in execution |
terragrunt init -reconfigure | Reconfigure backend, ignoring existing configuration |
terragrunt init -upgrade | Upgrade provider plugins to latest allowed versions |
terragrunt state pull > terraform.tfstate | Download and save remote state locally |
Configuration
Basic terragrunt.hcl Structure
# Include root configuration
include "root" {
path = find_in_parent_folders()
}
# Configure Terraform source
terraform {
source = "git::https://github.com/org/terraform-modules.git//vpc?ref=v1.0.0"
}
# Define inputs (variables)
inputs = {
environment = "production"
vpc_cidr = "10.0.0.0/16"
instance_type = "t3.medium"
}
Remote State Configuration (Root terragrunt.hcl)
# Configure remote state backend
remote_state {
backend = "s3"
generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}
config = {
bucket = "my-terraform-state-${get_aws_account_id()}"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Dependency Configuration
# Define dependencies between modules
dependency "vpc" {
config_path = "../vpc"
# Mock outputs for validation without dependencies applied
mock_outputs = {
vpc_id = "vpc-temporary-id"
}
mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}
# Use dependency outputs
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
subnet_ids = dependency.vpc.outputs.private_subnet_ids
}
Generate Provider Configuration
# Auto-generate provider configuration
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
Environment = "${local.environment}"
ManagedBy = "Terragrunt"
}
}
}
EOF
}
Locals and Functions
# Define local variables
locals {
environment = "production"
region = "us-east-1"
# Parse environment from path
parsed_path = regex(".*/environments/(?P<env>.*?)/.*", get_terragrunt_dir())
env_name = local.parsed_path.env
# Common tags
common_tags = {
Environment = local.environment
ManagedBy = "Terragrunt"
Project = "MyProject"
}
}
# Use locals in inputs
inputs = merge(
local.common_tags,
{
region = local.region
}
)
Hooks Configuration
# Execute commands before/after Terraform operations
terraform {
before_hook "before_init" {
commands = ["init"]
execute = ["echo", "Initializing Terraform..."]
}
after_hook "after_apply" {
commands = ["apply"]
execute = ["./scripts/notify-slack.sh"]
run_on_error = false
}
}
Common Use Cases
Use Case 1: Multi-Environment Infrastructure Setup
# Directory structure:
# └── environments/
# ├── terragrunt.hcl (root config)
# ├── dev/
# │ ├── vpc/terragrunt.hcl
# │ └── app/terragrunt.hcl
# └── prod/
# ├── vpc/terragrunt.hcl
# └── app/terragrunt.hcl
# Deploy entire dev environment
cd environments/dev
terragrunt run-all apply
# Deploy only VPC in production
cd environments/prod/vpc
terragrunt apply
# Plan all production changes
cd environments/prod
terragrunt run-all plan
Use Case 2: Managing Module Dependencies
# In app/terragrunt.hcl, reference VPC dependency:
# dependency "vpc" {
# config_path = "../vpc"
# }
# Apply app module (automatically applies VPC first if needed)
cd environments/dev/app
terragrunt apply --terragrunt-include-external-dependencies
# View dependency graph
cd environments/dev
terragrunt graph-dependencies | dot -Tpng > dependencies.png
Use Case 3: Local Module Development
# Override module source to test local changes
cd environments/dev/vpc
terragrunt plan --terragrunt-source ../../../modules/vpc-local
# Apply with local module
terragrunt apply --terragrunt-source ../../../modules/vpc-local
# Reset to remote source
terragrunt plan --terragrunt-source-update
Use Case 4: State Management and Migration
# List all resources in state
terragrunt state list
# Move resource to new address
terragrunt state mv aws_instance.old aws_instance.new
# Import existing AWS resource
terragrunt import aws_instance.web i-1234567890abcdef0
# Remove resource from state (keeps actual resource)
terragrunt state rm aws_instance.temporary
# Pull remote state for inspection
terragrunt state pull > backup.tfstate
Use Case 5: Debugging and Troubleshooting
# Enable debug logging
export TERRAGRUNT_LOG_LEVEL=debug
terragrunt plan
# Run with trace-level logging
terragrunt apply --terragrunt-log-level trace 2>&1 | tee debug.log
# Validate all configurations
terragrunt run-all validate
# Check formatting issues
terragrunt hclfmt --terragrunt-check
# Test configuration rendering
terragrunt render-json | jq '.'
Best Practices
- Use DRY principle: Keep backend configuration in root
terragrunt.hcl and include it in child modules using include blocks to avoid duplication
- Version your modules: Always pin module sources to specific versions or tags (e.g.,
?ref=v1.0.0) to ensure reproducible deployments
- Implement dependency management: Use
dependency blocks to explicitly define relationships between modules rather than relying on manual execution order
- Leverage locals and functions: Use Terragrunt’s built-in functions like
find_in_parent_folders(), get_aws_account_id(), and path_relative_to_include() for dynamic configuration
- Use mock outputs: Define
mock_outputs in dependency blocks to enable validation and planning without requiring all dependencies to be applied first
- Organize by environment: Structure directories by environment (dev/staging/prod) with shared configuration at the root level for consistency
- Enable state locking: Always configure DynamoDB tables for state locking when using S3 backend to prevent concurrent modification conflicts
- Use run-all carefully: Test with
run-all plan before run-all apply and consider using --terragrunt-parallelism to control concurrent executions
- Generate provider configs: Use
generate blocks to create provider configurations dynamically, ensuring consistency across modules
- Implement hooks for automation: Use
before_hook and after_hook to automate tasks like validation, notifications, or compliance checks
Troubleshooting
| Issue | Solution |
|---|
| Error: “No Terraform configuration files” | Ensure terraform.source is correctly specified in terragrunt.hcl and the source path exists. Run terragrunt init to download modules. |
| Backend initialization fails | Check AWS credentials and permissions. Verify S3 bucket and DynamoDB table exist or set skip_bucket_creation = false in remote_state config. |
| Dependency outputs not found | Ensure dependency module is applied first. Use mock_outputs for planning without dependencies. Check config_path points to correct directory. |
| ”Working directory already exists” error | Clear Terragrunt cache: rm -rf .terragrunt-cache then run terragrunt init again. Or use --terragrunt-source-update flag. |
| Module source not updating | Force source update with terragrunt init --terragrunt-source-update or delete .terragrunt-cache directory to clear cached modules. |
| State lock acquisition timeout | Another process holds the lock. Wait for completion or manually release lock in DynamoDB table. Check for crashed processes. |
| ”Module not found” with relative paths | Use find_in_parent_folders() to locate root config. Ensure relative paths account for Terragrunt’s working directory structure. |
| Run-all commands fail partially | Check individual module errors with --terragrunt-log-level debug. Verify dependencies are correctly defined. Use --terragrunt-ignore-dependency-errors cautiously. |
| Permission denied errors on AWS | Verify IAM role/user has required permissions. Check if role_arn in provider config is correct. Ensure MFA token is valid if required. |
| Circular dependency detected | Review dependency blocks to identify circular references. Restructure modules to break the cycle. Use terragrunt graph-dependencies to visualize. |
| Variables not being passed correctly | Check inputs block syntax in terragrunt.hcl. Verify variable names match module definitions. Use terragrunt render-json to inspect final config. |
| Performance issues with many modules | Adjust --terragrunt-parallelism to optimize concurrent executions. Consider splitting into smaller module groups. Use --terragrunt-include-dir for selective runs. |
| Terragrunt Command | Equivalent Terraform | Key Difference |
|---|
terragrunt init | terraform init | Auto-configures backend from terragrunt.hcl |
terragrunt plan | terraform plan | Includes Terragrunt-managed inputs and dependencies |
terragrunt apply | terraform apply | Processes dependencies and generates configs |
terragrunt run-all apply | N/A | Executes across multiple modules with dependency ordering |
terragrunt output | terraform output | Can aggregate outputs from multiple modules |