Skip to content

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.

Quick Reference: Terragrunt vs Terraform Commands

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
terragrunt graph-dependencies N/A Shows Terragrunt module dependencies (not resource graph)