Use when working with Terragrunt — DRY multi-env configs, module dependencies, remote state orchestration — even when the user just says 'deploy this to staging and prod' without naming Terragrunt.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add event4u-app/agent-config --skill terragrunt --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Terragrunt?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/event4u-app-terragrunt-agent-config)More formats (shields.io, HTML) on the badges page.
---
model_tier: medium
name: terragrunt
description: "Use when working with Terragrunt — DRY multi-env configs, module dependencies, remote state orchestration — even when the user just says 'deploy this to staging and prod' without naming Terragrunt."
domain: devops
workspaces:
- engineering
packs:
- engineering-base
---
# terragrunt
## When to use
Use this skill when working with Terragrunt configurations (`.hcl` files), managing environment-specific settings, or orchestrating multi-module deployments.
## Procedure: Write Terragrunt config
1. Read the `root.hcl` in the target environment (`environments/pro/root.hcl` or `environments/sta/root.hcl`).
2. Check existing `terragrunt.hcl` files in sibling directories for patterns.
3. Read the target module's `variables.tf` to understand required inputs.
## Project structure
```
environments/
├── pro/
│ ├── root.hcl # Root config (backend, providers)
│ ├── core/
│ │ ├── terragrunt.hcl # Core module config
│ │ └── {service}.yaml # Module-specific variables
│ ├── {service}/
│ │ ├── terragrunt.hcl # Service module config
│ │ └── {service}.yaml # Service-specific variables
│ └── ...
└── sta/
├── root.hcl
└── ...
```
## Root configuration (`root.hcl`)
The root HCL defines shared settings for all modules in an environment:
### Environment variables
```hcl
locals {
env_files = merge(
yamldecode(file(".env.yaml")), # Base env vars
try(yamldecode(file(".env.local.yaml")), {}) # Local overrides
)
env = { for k, v in local.env_files : k => get_env(k, v) }
}
```
- `.env.yaml` — committed, shared environment config
- `.env.local.yaml` — gitignored, local overrides (AWS profiles, etc.)
- Real environment variables take precedence over file values.
### Remote state
```hcl
remote_state {
backend = "s3"
config = {
bucket = "${local.env.aws_account_name}-terraform-remote-state"
key = "${path_relative_to_include()}/terraform.tfstate"
dynamodb_table = "${local.env.aws_account_name}-terraform-remote-state"
profile = local.env.aws_profile
region = local.env.aws_region
encrypt = true
}
}
```
### Provider generation
Providers are auto-generated by Terragrunt (not manually written):
```hcl
generate "provider" {
path = "provider-aws.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
allowed_account_ids = ["${local.env.aws_account_id}"]
profile = "${local.env.aws_profile}"
region = "${local.env.aws_region}"
}
EOF
}
```
### Terraform binary
```hcl
terraform_binary = "terraform" # Explicitly NOT OpenTofu
```
## Module configuration (`terragrunt.hcl`)
Each module directory contains a `terragrunt.hcl` that:
1. **Loads module-specific variables** from a YAML file
2. **Includes the root config** for backend and providers
3. **Points to the Terraform module source**
4. **Declares dependencies** on other modules
5. **Passes inputs** by merging dependency outputs with local variables
### Example pattern
```hcl
locals {
project = yamldecode(file("{service}.yaml"))
}
include {
path = find_in_parent_folders("root.hcl")
expose = true
}
terraform {
source = "../../..//modules/{service}"
}
dependency "core" {
config_path = "../core"
}
inputs = merge(
dependency.core.outputs,
local.project
)
```
## Conventions
### Variable files
- Use **YAML files** (not HCL) for module-specific variables.
- Name them after the module (e.g., `my-service.yaml`).
- Keep them in the same directory as `terragrunt.hcl`.
### Dependencies
- Use `dependency` blocks to reference other modules.
- Core module outputs (VPC, DNS zones, etc.) are passed via `dependency.core.outputs`.
- Merge dependency outputs with local variables in `inputs`.
### Additional providers
Some modules need extra providers (e.g., New Relic). Generate them in the module's `terragrunt.hcl`:
```hcl
generate "provider_newrelic" {
path = "provider-newrelic.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "newrelic" {
account_id = "${include.locals.env.newrelic_account_id}"
api_key = "${get_env("TF_VAR_newrelic_api_key", include.locals.env.newrelic_api_key)}"
}
EOF
}
```
## Development tools
The project uses **devbox** for tool management:
```json
{
"packages": ["terragrunt", "awscli2", "terraform@latest"]
}
```
### Quick commands (devbox scripts)
```bash
devbox run i # terragrunt init
devbox run p # terragrunt plan
devbox run a # terragrunt apply
devbox run d # terragrunt destroy
```
## Output format
1. Terragrunt HCL files with DRY environment configuration
2. Dependency graph and remote state references
## Auto-trigger keywords
- Terragrunt
- multi-environment
- DRY config
- remote state
## Gotcha
- Terragrunt `dependency` blocks create implicit ordering — circular dependencies cause cryptic errors.
- Don't duplicate Terraform variables in terragrunt.hcl — use `inputs` to pass them through.
- The model tends to hardcode values that should come from `include` blocks — use DRY patterns.
## Do NOT
- Do NOT switch to OpenTofu — the project explicitly uses `terraform_binary = "terraform"`.
- Do NOT hardcode AWS credentials — use AWS profiles from `.env.yaml`.
- Do NOT commit `.env.local.yaml` — it contains local AWS profile overrides.
- Do NOT modify `root.hcl` without understanding the impact on all modules.
- Do NOT remove `dependency` blocks — they ensure correct apply order.
- Do NOT use `terraform` commands directly — always use `terragrunt` as the wrapper.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!