Complete terragrunt toolkit with generation and validation capabilities
93
93%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Advisory
Suggest reviewing before use
Generate production-ready Terragrunt configurations following current best practices, naming conventions, and security standards. All generated configurations are automatically validated.
Terragrunt 2025 Features Supported:
terragrunt.stack.hcl (GA since v0.78.0)feature blocksskip)retryable_errors)RECOMMENDED: Use
root.hclinstead ofterragrunt.hclfor 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() |
CRITICAL: Before generating ANY configuration, determine the architecture pattern and understand its constraints.
| Pattern | Use When | Root Behavior | Structure |
|---|---|---|---|
| A: Multi-Env Agnostic | Multiple environments with shared root | Root reads NO env files; uses static values or get_env() | root.hcl + {env}/env.hcl per environment |
| B: Single/Env-Aware | Single environment OR environment detection needed | Root can parse path or read get_env() | root.hcl with optional account.hcl/region.hcl |
| C: Centralized Vars | Shared environment definitions | Root is agnostic; env.hcl reads from _env/ | root.hcl + _env/{env}.hcl + {env}/env.hcl |
Key principle: root.hcl does NOT read env.hcl. Child modules read env.hcl directly.
infrastructure/
├── root.hcl # Environment-AGNOSTIC
├── dev/env.hcl # locals { environment = "dev" }
│ └── vpc/terragrunt.hcl
└── prod/env.hcl # locals { environment = "prod" }
└── vpc/terragrunt.hclChild module pattern:
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" }Key principle: Root detects environment from path or environment variable.
# root.hcl
locals {
path_parts = split("/", path_relative_to_include())
environment = local.path_parts[0] # OR: get_env("TG_ENVIRONMENT", "dev")
}Key principle: Each env.hcl reads from centralized _env/{env}.hcl.
# prod/env.hcl
locals {
env_vars = read_terragrunt_config("${get_repo_root()}/_env/prod.hcl")
environment = local.env_vars.locals.environment
aws_region = local.env_vars.locals.aws_region
}Decision: Multi-env + shared root → A | Single env / env detection → B | Centralized vars → C
Create root-level root.hcl or terragrunt.hcl with remote state, provider config, and common variables.
Read before generating: 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_VERSION][ENVIRONMENT], [PROJECT_NAME]Root.hcl Design Principles:
get_env() for runtime configpath_relative_to_include() — Automatically includes environment pathCreate child modules with dependencies, mock outputs, and proper includes.
Read before generating: assets/templates/child/terragrunt.hcl
Patterns: references/common-patterns.md → Child Module Patterns
Module source options:
"../../modules/vpc""git::https://github.com/org/repo.git//path?ref=v1.0.0""tfr:///terraform-aws-modules/vpc/aws?version=5.1.0"Self-contained modules without root dependency.
Read before generating: assets/templates/module/terragrunt.hcl
Complete directory structures for dev/staging/prod.
Before generating:
Patterns: references/common-patterns.md → Environment-Specific Patterns
Typical structure (Pattern A):
infrastructure/
├── root.hcl # Environment-AGNOSTIC root config
├── dev/
│ ├── env.hcl # Dev environment variables
│ └── vpc/terragrunt.hcl
└── prod/
├── env.hcl # Prod environment variables
└── vpc/terragrunt.hclInfrastructure blueprints using terragrunt.stack.hcl.
Read before generating: assets/templates/stack/terragrunt.stack.hcl and assets/templates/catalog/terragrunt.hcl
Docs: Stacks Documentation
Patterns: references/common-patterns.md → Stacks Patterns
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 directoriesRuntime control without code changes.
Docs: Feature Flags Documentation
Patterns: references/common-patterns.md → Feature Flags Patterns
CRITICAL: Feature flag
defaultvalues MUST be static (boolean, string, number) — they CANNOT referencelocal.*values.
# Correct: static default
feature "enable_monitoring" {
default = false
}
# Incorrect: dynamic reference — FAILS
feature "enable_monitoring" {
default = local.env.locals.enable_monitoring
}Usage:
terragrunt apply --feature enable_monitoring=true
# or
export TG_FEATURE="enable_monitoring=true"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: Protect critical resources from accidental destruction:
exclude {
if = true
actions = ["destroy"]
exclude_dependencies = false
}
prevent_destroy = trueAdvanced error handling (replaces deprecated retryable_errors).
Docs: Errors Block Reference
Patterns: references/common-patterns.md → Errors Block Patterns
Use OpenTofu as the IaC engine.
Docs: Engine Documentation
Patterns: references/common-patterns.md → OpenTofu Engine Patterns
When generating configs with custom providers:
"[provider] terraform provider [version] documentation"required_providers blockCRITICAL: Follow this workflow for EVERY generation task. Skipping steps leads to validation errors.
| 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 |
MANDATORY: Before writing any files, complete and output this checklist to the user.
## 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| Configuration Type | Template to Read |
|---|---|
| Root configuration | assets/templates/root/terragrunt.hcl |
| Child module | assets/templates/child/terragrunt.hcl |
| Standalone module | assets/templates/module/terragrunt.hcl |
| Stack file | assets/templates/stack/terragrunt.stack.hcl |
| Catalog unit | assets/templates/catalog/terragrunt.hcl |
Also read: references/common-patterns.md — primary source for all generation patterns.
Generation order for multi-environment projects:
Generate root.hcl first
read_terragrunt_config(find_in_parent_folders("env.hcl")) if environment-agnosticremote_state block has encrypt = trueerrors block used (not deprecated retryable_errors)Generate env.hcl files for each environment
locals block contains environment, aws_region, and module-specific varsGenerate child modules — modules with NO dependencies first
include block uses find_in_parent_folders("root.hcl")read_terragrunt_config(find_in_parent_folders("env.hcl")) presentterraform.source uses valid syntax (tfr:///, git::, or relative path)Generate dependent modules (RDS, EKS, etc.)
dependency blocks have mock_outputsmock_outputs_allowed_terraform_commands includes ["validate", "plan", "destroy"]prevent_destroy = true and/or exclude blockRun batch validation after ALL files are generated:
terragrunt hcl fmt --check # Format validation
terragrunt dag graph # Dependency graph validationInvoke devops-skills:terragrunt-validator for comprehensive validation.
If validation fails:
Follow the Presentation Requirements section below.
Every generated configuration MUST be validated.
After generating root.hcl:
cd <infrastructure-directory>
terragrunt hcl fmt --checkAfter generating each child module:
cd <module-directory>
terragrunt hcl fmt --check
# If no dependencies on other modules:
terragrunt hcl validate --inputsAfter all files are generated:
devops-skills:terragrunt-validator skillSkip validation only for: Partial snippets, documentation examples, or explicit user request.
After successful validation, present ALL of the following sections.
tree <infrastructure-directory>| 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 |
| ... | ... |## Usage Instructions
### Prerequisites
1. AWS credentials 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
cd <INFRASTRUCTURE_DIR>
terragrunt run --all init # Initialize all modules
cd <ENV>/vpc && terragrunt plan # Preview a specific module
terragrunt run --all plan # Preview all changes
terragrunt run --all apply # Apply changes (requires approval)
terragrunt run --all destroy # Destroy (use with extreme caution)## 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 |Suggest what the user might want to do next (add more modules, customize configurations, etc.)
Reference ../devops-skills:terragrunt-validator/references/best_practices.md for comprehensive guidelines.
Key principles:
include blocks to inherit root configuration (DRY)encrypt = true)generate blocks for provider configuration~> 5.0, not >= 5.0) for local/Git modulesNote 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 ownrequired_providers. Omit generatingrequired_providersinroot.hclto avoid conflicts — the module's pinned version provides the constraint.
Anti-patterns to avoid:
| 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 |
For troubleshooting guidance, see references/troubleshooting.md, which covers:
path_relative_to_include() as a module source pathsource = "..//${path_relative_to_include()}" in a child module's terraform.source.get_parent_terragrunt_dir() or construct explicit relative paths from the root terragrunt.hcl location.terragrunt.hclremote_state {} blocks drift across units over time, creating inconsistent state key schemes and locking configurations that are difficult to audit.remote_state { backend = "s3" ... } block repeated in every leaf module.root.hcl and inherit it in every unit via include "root" { path = find_in_parent_folders("root.hcl") }.dependency output mismatches between plan and applydependency.outputs reference is evaluated and the dependency has not been applied, Terragrunt substitutes mock_outputs silently; if mock types differ from actual output types, the apply will fail with a type error.mock_outputs blocks with placeholder types and dismiss mock_outputs substitution warnings during terragrunt plan.mock_outputs whose types exactly match the actual dependency outputs, and use mock_outputs_allowed_terraform_commands = ["validate", "plan"] to limit substitution scope.terragrunt run --all apply without awareness of external dependency scoperun --all operations, which can produce partial applies that leave infrastructure in an inconsistent state.terragrunt run --all apply from a subdirectory expecting all transitive dependencies to be included automatically.--terragrunt-include-external-dependencies explicitly to ensure the full dependency graph is evaluated.terragrunt.hcl for both dev and prod environments without environment-level variable overridesterragrunt.hcl with no inputs block differentiation between environments.env.hcl files with inputs = { environment = "prod", instance_type = "m5.xlarge" } overrides that layer on top of shared defaults from the root configuration.| Configuration Type | Template File | When to Read |
|---|---|---|
| Root configuration | assets/templates/root/terragrunt.hcl | Before generating any root.hcl |
| Child module | assets/templates/child/terragrunt.hcl | Before generating any child module |
| Standalone module | assets/templates/module/terragrunt.hcl | Before generating standalone modules |
| Stack file | assets/templates/stack/terragrunt.stack.hcl | Before generating stacks |
| Catalog unit | assets/templates/catalog/terragrunt.hcl | Before generating catalog units |
| Reference | Content | When to Read |
|---|---|---|
references/common-patterns.md | All generation patterns with examples | Always, before generating |
references/troubleshooting.md | Common issues and fixes | When encountering errors |
../devops-skills:terragrunt-validator/references/best_practices.md | Comprehensive best practices | Always, before generating |