- Terragrunt Generator
- Overview
- Generate production-ready Terragrunt configurations following current best practices, naming conventions, and security standards. All generated configurations are automatically validated.
- Trigger Phrases
- Use this skill when the user asks for:
- A new
- root.hcl
- ,
- terragrunt.hcl
- , or
- terragrunt.stack.hcl
- Multi-environment Terragrunt layouts (
- dev/staging/prod
- )
- Terragrunt dependency wiring (
- dependency
- or
- dependencies
- blocks)
- Terragrunt module source setup (local, Git, Terraform Registry via
- tfr:///
- )
- Stack catalog unit generation under
- catalog/units/*
- Terragrunt 2025 Features Supported:
- Stacks
- - Infrastructure blueprints with
- terragrunt.stack.hcl
- (GA since v0.78.0)
- Feature Flags
- - Runtime control via
- feature
- blocks
- Exclude Blocks
- - Fine-grained execution control (replaces deprecated
- skip
- )
- Errors Blocks
- - Advanced error handling (replaces deprecated
- retryable_errors
- )
- OpenTofu Engine
- - Alternative IaC engine support
- Root Configuration Naming
- RECOMMENDED
- Use root.hcl instead of terragrunt.hcl for root files per migration guide . Approach Root File Include Syntax Modern root.hcl find_in_parent_folders("root.hcl") Legacy terragrunt.hcl find_in_parent_folders() Include standard: Default to find_in_parent_folders("root.hcl") in all new examples and generated configs. Use find_in_parent_folders() only when explicitly targeting a legacy root file named terragrunt.hcl . Architecture Patterns CRITICAL: Before generating ANY configuration, you MUST determine the architecture pattern and understand its constraints. Pattern A: Multi-Environment with Environment-Agnostic Root Use when: Managing multiple environments (dev/staging/prod) with shared root configuration. Key principle: root.hcl is environment-agnostic - it does NOT read environment-specific files. infrastructure/ ├── root.hcl # Environment-AGNOSTIC (no env.hcl references) ├── dev/ │ ├── env.hcl # Environment variables (locals block) │ ├── vpc/terragrunt.hcl │ └── rds/terragrunt.hcl └── prod/ ├── env.hcl # Environment variables (locals block) ├── vpc/terragrunt.hcl └── rds/terragrunt.hcl Root.hcl constraints: ❌ CANNOT use read_terragrunt_config(find_in_parent_folders("env.hcl")) - env.hcl doesn't exist at root level ❌ CANNOT reference local.environment or local.aws_region that come from env.hcl ✅ CAN use static values or get_env() for runtime configuration ✅ CAN use ${path_relative_to_include()} for state keys (this works dynamically) Child modules read env.hcl:
dev/vpc/terragrunt.hcl
include "root" { path = find_in_parent_folders( "root.hcl" ) } locals { env = read_terragrunt_config(find_in_parent_folders( "env.hcl" )) } inputs = { name = " $ { local . env . locals . environment } -vpc"
Works: env.hcl exists in dev/
} Pattern B: Single Environment or Environment-Aware Root Use when: Single environment OR all environments share the same root with environment detection. infrastructure/ ├── root.hcl # Can be environment-aware via get_env() or directory parsing ├── account.hcl # Account-level config (optional) ├── region.hcl # Region-level config (optional) └── vpc/ └── terragrunt.hcl Root.hcl can detect environment:
root.hcl - environment detection via directory path
locals {
Parse environment from path (e.g., "prod/vpc" -> "prod")
path_parts
split( "/" , path_relative_to_include()) environment = local.path_parts [ 0 ]
OR use environment variable
environment
get_env( "TG_ENVIRONMENT" , "dev" ) } Pattern C: Shared Environment Variables (_env directory) Use when: Centralizing environment variables with symlinks or direct references. infrastructure/ ├── root.hcl # Environment-AGNOSTIC ├── _env/ # Centralized environment definitions │ ├── prod.hcl │ ├── staging.hcl │ └── dev.hcl ├── prod/ │ ├── env.hcl # Reads from _env/prod.hcl │ └── vpc/terragrunt.hcl └── dev/ ├── env.hcl # Reads from _env/dev.hcl └── vpc/terragrunt.hcl env.hcl reads from _env:
prod/env.hcl
locals { env_vars = read_terragrunt_config( " $ { get_repo_root ( ) } /_env/prod.hcl" )
Re-export for child modules
environment
local.env_vars.locals.environment aws_region = local.env_vars.locals.aws_region vpc_cidr = local.env_vars.locals.vpc_cidr
... other variables
} Architecture Pattern Selection Checklist (Canonical) MANDATORY: Before writing any files, you MUST complete this checklist and OUTPUT it to the user with checkmarks filled in. This is not optional. Output this completed checklist before generating any files:
Architecture Pattern Selection
[x] Identified architecture pattern: Pattern ___ (A/B/C) [x] Root.hcl scope: [ ] environment-agnostic OR [ ] environment-aware [x] env.hcl location: ___ [x] Child modules access env via: _____ [x] Verified: No file references a path that doesn't exist from its location Example completed checklist:
Architecture Pattern Selection
[x] Identified architecture pattern: Pattern A (Multi-Environment with Environment-Agnostic Root) [x] Root.hcl scope: [x] environment-agnostic OR [ ] environment-aware [x] env.hcl location: dev/env.hcl, prod/env.hcl (one per environment) [x] Child modules access env via: read_terragrunt_config(find_in_parent_folders("env.hcl")) [x] Verified: No file references a path that doesn't exist from its location Quick Variable Definition Examples Use these starter files for Pattern B and account/region-aware setups. env.hcl locals { environment = "dev" aws_region = "us-east-1" project = "platform" } account.hcl locals { account_id = "123456789012" account_name = "shared-services" } region.hcl locals { aws_region = "us-east-1" } When to Use Creating new Terragrunt projects or configurations Setting up multi-environment infrastructure (dev/staging/prod) Implementing DRY Terraform configurations Managing complex infrastructure with dependencies Working with custom Terraform providers or modules Core Capabilities 1. Generate Root Configuration Create root-level root.hcl or terragrunt.hcl with remote state, provider config, and common variables. MANDATORY: Before generating, READ the template file: Read: assets/templates/root/terragrunt.hcl Template: assets/templates/root/terragrunt.hcl Patterns: references/common-patterns.md → Root Configuration Patterns Key placeholders to replace: [BUCKET_NAME] , [AWS_REGION] , [DYNAMODB_TABLE] [TERRAFORM_VERSION] , [PROVIDER_NAME] , [PROVIDER_SOURCE] , [PROVIDER_VERSION] [ENVIRONMENT] , [PROJECT_NAME] Root.hcl Design Principles: Environment-agnostic by default - Don't assume env.hcl exists at root level Use static values for provider/backend region - Or use get_env() for runtime config State key uses path_relative_to_include() - This automatically includes environment path Provider tags can be static - Environment-specific tags go in child modules 2. Generate Child Module Configuration Create child modules with dependencies, mock outputs, and proper includes. MANDATORY: Before generating, READ the template file: Read: assets/templates/child/terragrunt.hcl Template: assets/templates/child/terragrunt.hcl Patterns: references/common-patterns.md → Child Module Patterns Module source options: Local: "../../modules/vpc" Git: "git::https://github.com/org/repo.git//path?ref=v1.0.0" Registry: "tfr:///terraform-aws-modules/vpc/aws?version=5.1.0" 3. Generate Standalone Module Self-contained modules without root dependency. MANDATORY: Before generating, READ the template file: Read: assets/templates/module/terragrunt.hcl Template: assets/templates/module/terragrunt.hcl Canonical Placeholder Replacement Map Use this map for every generated output: Placeholder Meaning Example Replacement Notes [AWS_REGION] AWS region us-east-1 Canonical region placeholder in all templates [ENVIRONMENT] Environment name dev Keep lowercase for directory naming [PROJECT_NAME] Project/application name payments-platform Use the same value in tags and names [BUCKET_NAME] Remote state S3 bucket acme-tfstate-prod Bucket must exist before first apply [DYNAMODB_TABLE] State lock table acme-terraform-locks Table must exist before first apply [PROVIDER_SOURCE] Terraform provider source hashicorp/aws Use fully qualified source [TERRAFORM_VERSION] Required Terraform/OpenTofu version 1.8.5 Used in both terraform_version_constraint and required_version . Keep compatible with module constraints. Legacy alias normalization: If you see [REGION] in older examples, treat it as [AWS_REGION] and replace it before validation. 4. Generate Multi-Environment Infrastructure Complete directory structures for dev/staging/prod. MANDATORY: Before generating: Determine architecture pattern (see Architecture Patterns section) Read relevant templates for root, env, and child modules Verify env.hcl placement and access patterns: Read: assets/templates/env/env.hcl Patterns: references/common-patterns.md → Environment-Specific Patterns Typical structure (Pattern A - Environment-Agnostic Root): infrastructure/ ├── root.hcl # Environment-AGNOSTIC root config ├── dev/ │ ├── env.hcl # Dev environment variables │ └── vpc/terragrunt.hcl └── prod/ ├── env.hcl # Prod environment variables └── vpc/terragrunt.hcl 5. Generate Terragrunt Stacks (2025) Infrastructure blueprints using terragrunt.stack.hcl . MANDATORY: Before generating, READ the template files: Read: assets/templates/stack/terragrunt.stack.hcl Read: assets/templates/catalog/terragrunt.hcl Docs: Stacks Documentation Template: assets/templates/stack/terragrunt.stack.hcl Catalog Template: assets/templates/catalog/terragrunt.hcl Patterns: references/common-patterns.md → Stacks Patterns Stack path rule: Keep no_dot_terragrunt_stack mode consistent across dependent units. Do not mix direct-path and .terragrunt-stack generation in the same dependency chain. Commands: terragrunt stack generate
Generate unit configurations
terragrunt stack run plan
Plan all units
terragrunt stack run apply
Apply all units
terragrunt stack output
Get aggregated outputs
terragrunt stack clean
Clean generated directories
- Generate Feature Flags (2025) Runtime control without code changes. Docs: Feature Flags Documentation Patterns: references/common-patterns.md → Feature Flags Patterns CRITICAL: Feature flag default values MUST be static (boolean, string, number). They CANNOT reference local.* values. Use static defaults and override via CLI/env vars. Correct: feature "enable_monitoring" { default = false
Static value - OK
} Incorrect: feature "enable_monitoring" { default = local.env.locals.enable_monitoring
Dynamic reference - FAILS
} Usage: terragrunt apply --feature enable_monitoring = true
or
export TG_FEATURE = "enable_monitoring=true" Environment-specific defaults: Use different static defaults per environment file, not dynamic references. 7. Generate Exclude Blocks (2025) Fine-grained execution control (replaces deprecated skip ). Docs: Exclude Block Reference Patterns: references/common-patterns.md → Exclude Block Patterns Actions: "plan" , "apply" , "destroy" , "all" , "all_except_output" Production Recommendation: For critical production resources, add exclude blocks to prevent accidental destruction:
Protect production databases from accidental destroy
exclude { if = true actions = [ "destroy" ] exclude_dependencies = false }
Also use prevent_destroy for critical resources
prevent_destroy
true 8. Generate Errors Blocks (2025) Advanced error handling (replaces deprecated retryable_errors ). Docs: Errors Block Reference Patterns: references/common-patterns.md → Errors Block Patterns 9. Generate OpenTofu Engine Configuration (2025) Use OpenTofu as the IaC engine. Docs: Engine Documentation Patterns: references/common-patterns.md → OpenTofu Engine Patterns 10. Handling Custom Providers/Modules When generating configs with custom providers: Identify the provider name, source, and version Search using WebSearch: "[provider] terraform provider [version] documentation" Or use Context7 MCP if available for structured docs Generate with proper required_providers block Document authentication requirements in comments Generation Workflow CRITICAL: Follow this workflow for EVERY generation task. Skipping steps leads to validation errors. Step 1: Understand Requirements What type of configuration? (root, child, standalone, stack) Single or multi-environment? What dependencies exist between modules? What providers/modules will be used? Step 2: Determine Architecture Pattern MANDATORY: Select and document the pattern BEFORE writing any files. Scenario Pattern Root.hcl Scope Multi-env with shared root Pattern A Environment-agnostic Single environment Pattern B Environment-aware Centralized env vars Pattern C Environment-agnostic Complete the Architecture Pattern Selection Checklist (Canonical) above and include it in output before file generation. Step 3: Read Required Templates MANDATORY: Read the relevant template file(s) BEFORE generating each configuration type. Configuration Type Template to Read Purpose Root configuration assets/templates/root/terragrunt.hcl Shared state backend, providers, and common inputs Environment variables assets/templates/env/env.hcl Per-environment locals read by child modules (Pattern A) Child module assets/templates/child/terragrunt.hcl Environment module wired to root include Standalone module assets/templates/module/terragrunt.hcl Independent Terragrunt module without root include Stack file assets/templates/stack/terragrunt.stack.hcl Blueprint that generates multiple units Catalog unit assets/templates/catalog/terragrunt.hcl Reusable unit template consumed by stacks Also read: references/common-patterns.md - Primary source for generation patterns Step 4: Generate with Validation Validation Strategy: Use a combination of inline checks during generation and batch validation at the end. Generation order for multi-environment projects: Generate root.hcl first Inline checks (during generation): No read_terragrunt_config(find_in_parent_folders("env.hcl")) if environment-agnostic remote_state block has encrypt = true errors block used (not deprecated retryable_errors ) Generate env.hcl files for each environment Inline checks (during generation): locals block contains environment, aws_region, and module-specific vars No references to files that don't exist at that directory level Generate child modules (VPC, etc.) - modules with NO dependencies first Inline checks (during generation): include block uses find_in_parent_folders("root.hcl") read_terragrunt_config(find_in_parent_folders("env.hcl")) present terraform.source uses valid syntax ( tfr:/// , git:: , or relative path) Generate dependent modules (RDS, EKS, etc.) Inline checks (during generation): dependency blocks have mock_outputs mock_outputs_allowed_terraform_commands includes ["validate", "plan", "destroy"] Production modules have prevent_destroy = true and/or exclude block Run batch validation after ALL files are generated Note: Full CLI validation ( terragrunt hcl fmt , terragrunt dag graph ) requires all files to exist, so these are batched at the end.
Batch validation commands (run after all files exist):
terragrunt hcl fmt --check
Format validation
terragrunt dag graph
Dependency graph validation
Invoke Skill(devops-skills:terragrunt-validator) for comprehensive validation Step 5: Fix and Re-Validate If validation fails: Analyze errors (path resolution, missing variables, syntax errors) Fix issues in the specific file(s) Re-validate the fixed file(s) Repeat until ALL errors are resolved Step 6: Present Results Follow "Presentation Requirements" section below. Validation Workflow CRITICAL: Every generated configuration MUST be validated. Incremental Validation Checks After generating root.hcl: cd < infrastructure-directory
terragrunt hcl fmt --check After generating each child module: cd < module-directory
terragrunt hcl fmt --check
If no dependencies on other modules:
terragrunt hcl validate --inputs Full Validation After all files are generated: Invoke validation skill: Invoke: Skill(devops-skills:terragrunt-validator) If validation fails: Analyze errors (missing placeholders, invalid syntax, wrong paths) Fix issues Re-validate (repeat until ALL errors are resolved) If validation succeeds: Present configurations with usage instructions Skip validation only for: Partial snippets, documentation examples, or explicit user request Validation Fallbacks (Environment Constraints) If the normal validation path is unavailable, use this fallback order and report what was skipped: If terragrunt is unavailable: Run static checks: rg -n "[[A-Z0-9_]+]" . rg -n "find_in_parent_folders \ ( \" env \ .hcl \" \ )" . Report that runtime Terragrunt validation is pending. If validator skill execution is unavailable: Run direct Terragrunt checks instead: terragrunt hcl fmt --check terragrunt dag graph If tree is unavailable for presentation: Use: find . -maxdepth 4 -type f | sort Presentation Requirements MANDATORY: After successful validation, you MUST present ALL of the following sections. Incomplete presentation is not acceptable. Copy and fill in the templates below. 1. Directory Structure Summary (MANDATORY)
Show the generated structure
tree < infrastructure-directory
- Files Generated (MANDATORY) Output this table with all generated files: | File | Purpose | |
|
| | root.hcl | Shared configuration for all child modules (state backend, provider) | | dev/env.hcl | Development environment variables | | prod/env.hcl | Production environment variables | | dev/vpc/terragrunt.hcl | VPC module for development | | ... | ... | 3. Usage Instructions (MANDATORY) You MUST include this section. Copy the template below and fill in the actual values:
Usage Instructions
Prerequisites
Before running Terragrunt commands, ensure:
1.
AWS credentials are configured (
aws configure
or environment variables)
2.
S3 bucket
<BUCKET_NAME>
exists for state storage
3.
DynamoDB table
<TABLE_NAME>
exists for state locking
Commands
Navigate to infrastructure directory cd < INFRASTRUCTURE_DIR
Initialize all modules terragrunt run --all init
Preview changes for a specific environment cd < ENV
/vpc && terragrunt plan
Preview all changes terragrunt run --all plan
Apply changes (requires approval) terragrunt run --all apply
Destroy (use with extreme caution) terragrunt run --all destroy 4. Placeholder Replacement and Secrets Check (MANDATORY) You MUST include this section. Copy the template below and fill in the actual values:
Placeholder and Secrets Check
Placeholder Replacement
[ ] All placeholders (
[AWS_REGION]
,
[BUCKET_NAME]
,
[DYNAMODB_TABLE]
, etc.) replaced with real values
-
[ ] No legacy placeholder aliases left (for example
[REGION]
)
-
[ ]
terraform.source
values point to real module sources and pinned versions
Secrets Safety
[ ] No plaintext credentials or access keys in
terragrunt.hcl
,
root.hcl
,
env.hcl
,
account.hcl
, or
region.hcl
-
[ ] Sensitive values sourced via environment variables, secret managers, or CI variables
-
[ ] Example values kept non-sensitive and clearly marked as placeholders
5. Environment-Specific Notes (MANDATORY)
You MUST include this section.
Copy the template below and fill in the actual values:
Environment Notes
Required Environment Variables | Variable | Description | Example | |
|
|
|
|
AWS_PROFILE
|
AWS CLI profile to use
|
my-profile
|
|
AWS_REGION
|
AWS region (or set in provider)
|
us-east-1
|
Prerequisites
[ ] S3 bucket
<BUCKET_NAME>
must exist before first run
-
[ ] DynamoDB table
<TABLE_NAME>
must exist for state locking
-
[ ] IAM permissions for Terraform state management
Production-Specific Protections | Module | Protection | Description | |
|
|
|
|
prod/rds
|
prevent_destroy = true
|
Prevents accidental database deletion
|
|
prod/rds
|
exclude { actions = ["destroy"] }
|
Blocks destroy commands
|
6. Next Steps (Optional)
Suggest what the user might want to do next (add more modules, customize configurations, etc.)
Best Practices
Reference
../terragrunt-validator/references/best_practices.md
for comprehensive guidelines.
Key principles:
Use
include
blocks to inherit root configuration (DRY)
Always provide mock outputs for dependencies
Enable state encryption (
encrypt = true
)
Use
generate
blocks for provider configuration
Specify bounded version constraints (
~> 5.0
, not
= 5.0 ) for local/Git modules Never hardcode credentials or secrets Configure retry logic for transient errors Note on Version Constraints with Registry Modules: When using Terraform Registry modules (e.g., tfr:///terraform-aws-modules/vpc/aws?version=5.1.0 ), they typically define their own required_providers . In this case, you may omit generating required_providers in root.hcl to avoid conflicts. The module's pinned version ( ?version=X.X.X ) provides the version constraint. See "Common Issues → Provider Conflict with Registry Modules" for details. Anti-patterns to avoid: Hardcoded account IDs, regions, or environment names Missing mock outputs for dependencies Duplicated configuration across modules Unencrypted state storage Missing or loose version constraints (except when using registry modules that define their own) Root.hcl trying to read env.hcl that doesn't exist at root level Deprecated Attributes Deprecated Replacement Reference skip exclude block Docs retryable_errors errors.retry block Docs run-all run --all Migration --terragrunt- flags Unprefixed flags CLI Reference TERRAGRUNT_ env vars TG_* env vars CLI Reference Resources Templates - MUST Read Before Generating Configuration Type Template File Purpose When to Read Root configuration assets/templates/root/terragrunt.hcl Shared backend, provider, and common inputs Before generating any root.hcl Environment variables assets/templates/env/env.hcl Per-environment locals (environment, region, sizing, feature toggles) Before generating any env.hcl (Pattern A) Child module assets/templates/child/terragrunt.hcl Module include, source, and optional dependency scaffolding Before generating any child module Standalone module assets/templates/module/terragrunt.hcl Module config without root inheritance Before generating standalone modules Stack file assets/templates/stack/terragrunt.stack.hcl Stack blueprint and unit generation Before generating stacks Catalog unit assets/templates/catalog/terragrunt.hcl Reusable unit consumed by stack definitions Before generating catalog units References Reference Content Purpose When to Read references/common-patterns.md All generation patterns with examples Pick a compatible pattern before writing files Always, before generating ../terragrunt-validator/references/best_practices.md Comprehensive best practices Final quality and safety checks Always, before generating Official Documentation Terragrunt Docs Configuration Reference CLI Reference Stacks Feature Flags Engine Migration Guides Common Issues Root.hcl Cannot Find env.hcl Symptom: Error: Attempt to get attribute from null value on ./root.hcl line X: This value is null, so it does not have any attributes. Cause: Root.hcl is trying to read env.hcl via find_in_parent_folders("env.hcl") , but env.hcl doesn't exist at the root level. Solution: Make root.hcl environment-agnostic:
DON'T do this in root.hcl for multi-environment setups:
locals { env_vars = read_terragrunt_config(find_in_parent_folders( "env.hcl" ))
FAILS
}
DO use static values or get_env():
generate "provider" { path = "provider.tf" if_exists = "overwrite_terragrunt" contents = <<EOF provider "aws" { region = "us-east-1" # Static value, or use get_env("AWS_REGION", "us-east-1") } EOF } Provider Conflict with Registry Modules When using Terraform Registry modules (e.g., tfr:///terraform-aws-modules/vpc/aws ), they may define their own required_providers block. This can conflict with provider configuration generated by root.hcl . Symptoms: Error: Duplicate required providers configuration Solutions: Remove conflicting generate block - If using registry modules that manage their own providers, avoid generating duplicate required_providers :
In root.hcl - only generate provider config, not required_providers
generate "provider" { path = "provider.tf" if_exists = "overwrite_terragrunt" contents = <<EOF provider "aws" { region = "us-east-1" } EOF } Use if_exists = "skip" - Skip generation if file already exists: generate "versions" { path = "versions.tf" if_exists = "skip"
Don't overwrite module's versions.tf
contents
"..." } Clear cache - If conflicts persist after fixes: rm -rf .terragrunt-cache terragrunt init Feature Flag Validation Errors If you see Unknown variable; There is no variable named "local" in feature blocks, ensure defaults are static values (see Feature Flags section above). Child Module Cannot Find env.hcl Symptom: Error: Attempt to get attribute from null value on ./dev/vpc/terragrunt.hcl line X: Cause: Child module's find_in_parent_folders("env.hcl") cannot find env.hcl. Solution: Ensure env.hcl exists in the environment directory: dev/ ├── env.hcl # This file MUST exist └── vpc/ └── terragrunt.hcl # Calls find_in_parent_folders("env.hcl") Quick Reference Card File Reading Checklist Before generating, READ these files in order: references/common-patterns.md - Understand available patterns ../terragrunt-validator/references/best_practices.md - Know the rules Relevant template(s) from assets/templates/ - Structural reference Architecture Decision Tree Q: Multiple environments (dev/staging/prod)? ├─ YES → Q: Shared root configuration? │ ├─ YES → Pattern A: Environment-Agnostic Root │ └─ NO → Separate root.hcl per environment └─ NO → Q: Environment detection needed? ├─ YES → Pattern B: Environment-Aware Root └─ NO → Pattern B: Simple single-environment Validation Sequence Format check: terragrunt hcl fmt --check Input validation: terragrunt hcl validate --inputs Full validation: Invoke Skill(devops-skills:terragrunt-validator) Fix errors → Re-validate → Repeat until clean Done Criteria This skill execution is complete only when ALL are true: One architecture checklist is completed and shown (the canonical checklist in this file) Generated files consistently use modern root include syntax unless legacy was explicitly requested Registry sources use canonical tfr:///NAMESPACE/NAME/PROVIDER?version=X.Y.Z format Dependency blocks are added only where actually needed (not left as unresolved placeholders) All placeholders are replaced and secrets checks are reported in output Validation succeeded, or fallback checks ran with explicit limitations documented