Skip to content
Back to skills

Terragrunt

ASecurity

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.

  • 10 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added June 5, 2026
ai-agentsgobashawsterraformgitapibackenddevops

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 2, 2026

npx -y skills add event4u-app/agent-config --skill terragrunt --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Terragrunt?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Terragrunt
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/event4u-app-terragrunt/badge)](https://www.skillsdirectory.com/skills/event4u-app-terragrunt)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.