---
title: "Terragrunt Common Generation Patterns"
description: "This reference provides common patterns and code examples for generating Terragrunt configurations. Use these patterns as building blocks when creating new Terragrunt resources."
type: skill
canonical_url: https://claudary.paisolsolutions.com/skills/common-patterns-1
source: "Claudary"
difficulty: intermediate
author: "Claude Code Knowledge Pack"
date: 2026-07-10T11:18:31.733Z
license: CC-BY-4.0
attribution: "Terragrunt Common Generation Patterns — Claudary (https://claudary.paisolsolutions.com/skills/common-patterns-1)"
---

# Terragrunt Common Generation Patterns
This reference provides common patterns and code examples for generating Terragrunt configurations. Use these patterns as building blocks when creating new Terragrunt resources.

## Overview

# Terragrunt Common Generation Patterns

## Overview

This reference provides common patterns and code examples for generating Terragrunt configurations. Use these patterns as building blocks when creating new Terragrunt resources.

> **Include syntax standard:** Use `find_in_parent_folders("root.hcl")` for new projects. Only use `find_in_parent_folders()` when the repository intentionally keeps a legacy root file named `terragrunt.hcl`.

## Root Configuration Patterns

### Pattern 1: Basic Root with S3 Backend

**Use when:** Starting a new Terragrunt project with AWS S3 backend

```hcl
# root.hcl (modern root file name)
remote_state {
  backend = "s3"
  config = {
    bucket         = "company-terraform-state"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
provider "aws" {
  region = var.region
}
EOF
}

inputs = {
  region = "us-east-1"
  common_tags = {
    ManagedBy = "Terragrunt"
  }
}
```

### Pattern 2: Multi-Account Root Configuration

**Use when:** Managing multiple AWS accounts with role assumption

```hcl
# root.hcl (modern root file name)
locals {
  account_vars = read_terragrunt_config(find_in_parent_folders("account.hcl"))
  region_vars  = read_terragrunt_config(find_in_parent_folders("region.hcl"))
  env_vars     = read_terragrunt_config(find_in_parent_folders("env.hcl"))

  account_id  = local.account_vars.locals.account_id
  region      = local.region_vars.locals.region
  environment = local.env_vars.locals.environment
}

remote_state {
  backend = "s3"
  config = {
    bucket         = "terraform-state-${local.account_id}"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = local.region
    encrypt        = true
    dynamodb_table = "terraform-locks-${local.environment}"

    role_arn = "arn:aws:iam::${local.account_id}:role/TerraformRole"
  }
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
provider "aws" {
  region = "${local.region}"

  assume_role {
    role_arn = "arn:aws:iam::${local.account_id}:role/TerraformRole"
  }

  default_tags {
    tags = {
      Environment = "${local.environment}"
      ManagedBy   = "Terragrunt"
    }
  }
}
EOF
}

inputs = {
  account_id  = local.account_id
  region      = local.region
  environment = local.environment
}
```

### Pattern 3: Multi-Cloud Root Configuration

**Use when:** Managing resources across multiple cloud providers

```hcl
# root.hcl (modern root file name)
generate "providers" {
  path      = "providers.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}

provider "azurerm" {
  features {}
  subscription_id = var.azure_subscription_id
}

provider "google" {
  project = var.gcp_project
  region  = var.gcp_region
}
EOF
}
```

## Child Module Patterns

### Pattern 1: Simple Module with No Dependencies

**Use when:** Creating standalone infrastructure component

```hcl
# modules/vpc/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "tfr:///terraform-aws-modules/vpc/aws?version=5.1.0"
}

inputs = {
  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b", "us-east-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = true
  enable_vpn_gateway = false

  tags = {
    Name = "my-vpc"
  }
}
```

### Pattern 2: Module with Single Dependency

**Use when:** Creating a resource that depends on another module's outputs

```hcl
# modules/rds/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "tfr:///terraform-aws-modules/rds/aws?version=6.1.0"
}

dependency "vpc" {
  config_path = "../vpc"

  mock_outputs = {
    vpc_id             = "vpc-mock123"
    database_subnet_ids = ["subnet-mock1", "subnet-mock2"]
  }

  mock_outputs_allowed_terraform_commands = ["validate", "plan", "destroy"]
}

dependency "security_group" {
  config_path = "../security-groups/database"

  mock_outputs = {
    security_group_id = "sg-mock123"
  }

  mock_outputs_allowed_terraform_commands = ["validate", "plan", "destroy"]
}

inputs = {
  identifier = "mydb"
  engine     = "postgres"

  vpc_security_group_ids = [dependency.security_group.outputs.security_group_id]
  db_subnet_group_name   = dependency.vpc.outputs.database_subnet_group_name

  allocated_storage = 20
  instance_class    = "db.t3.micro"
}
```

### Pattern 3: Module with Multiple Dependencies

**Use when:** Creating complex infrastructure with multiple upstream dependencies

```hcl
# modules/eks/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "tfr:///terraform-aws-modules/eks/aws?version=19.15.0"
}

dependencies {
  paths = ["../vpc", "../security-groups", "../iam-roles"]
}

dependency "vpc" {
  config_path = "../vpc"

  mock_outputs = {
    vpc_id             = "vpc-mock"
    private_subnet_ids = ["subnet-1", "subnet-2"]
  }
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}

dependency "security_groups" {
  config_path = "../security-groups"

  mock_outputs = {
    cluster_security_group_id = "sg-mock"
  }
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}

dependency "iam" {
  config_path = "../iam-roles"

  mock_outputs = {
    cluster_role_arn = "arn:aws:iam::123456789012:role/mock-role"
  }
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}

inputs = {
  cluster_name    = "my-eks-cluster"
  cluster_version = "1.28"

  vpc_id     = dependency.vpc.outputs.vpc_id
  subnet_ids = dependency.vpc.outputs.private_subnet_ids

  cluster_security_group_id = dependency.security_groups.outputs.cluster_security_group_id
  iam_role_arn              = dependency.iam.outputs.cluster_role_arn

  enable_irsa = true
}
```

### Pattern 4: Module with Conditional Logic

**Use when:** Generating configurations with environment-specific variations

```hcl
# modules/app/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

locals {
  env = get_env("ENVIRONMENT", "dev")

  instance_counts = {
    dev  = 1
    staging = 2
    prod = 3
  }

  instance_types = {
    dev  = "t3.micro"
    staging = "t3.small"
    prod = "t3.medium"
  }
}

terraform {
  source = "../../terraform-modules/app"
}

inputs = {
  environment    = local.env
  instance_count = local.instance_counts[local.env]
  instance_type  = local.instance_types[local.env]

  enable_monitoring = local.env == "prod" ? true : false
  enable_backups    = local.env == "prod" ? true : false

  tags = merge(
    {
      Environment = local.env
      ManagedBy   = "Terragrunt"
    },
    local.env == "prod" ? { CriticalResource = "true" } : {}
  )
}
```

## Environment-Specific Patterns

### Pattern 1: Environment Configuration Files

**Use when:** Managing multiple environments with shared structure

```
infrastructure/
├── root.hcl                 # Root config (modern)
├── _env/
│   ├── prod.hcl            # Production variables
│   ├── staging.hcl         # Staging variables
│   └── dev.hcl             # Development variables
├── prod/
│   ├── env.hcl -> ../_env/prod.hcl
│   └── vpc/
│       └── terragrunt.hcl
└── staging/
    ├── env.hcl -> ../_env/staging.hcl
    └── vpc/
        └── terragrunt.hcl
```

**_env/prod.hcl:**
```hcl
locals {
  environment = "prod"
  region      = "us-east-1"

  vpc_cidr = "10.0.0.0/16"

  instance_type = "t3.medium"
  min_size      = 3
  max_size      = 10
}
```

**prod/vpc/terragrunt.hcl:**
```hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

locals {
  env = read_terragrunt_config(find_in_parent_folders("env.hcl"))
}

terraform {
  source = "tfr:///terraform-aws-modules/vpc/aws?version=5.1.0"
}

inputs = {
  name = "${local.env.locals.environment}-vpc"
  cidr = local.env.locals.vpc_cidr

  azs = ["${local.env.locals.region}a", "${local.env.locals.region}b"]
}
```

## Advanced Patterns

### Pattern 1: Dynamic Provider Configuration

**Use when:** Provider configuration varies by module or environment

```hcl
# modules/cross-account-resource/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

locals {
  target_account_id = "987654321098"
}

generate "provider_override" {
  path      = "provider_override.tf"
  if_exists = "overwrite"
  contents  = <<EOF
provider "aws" {
  alias  = "target_account"
  region = var.region

  assume_role {
    role_arn = "arn:aws:iam::${local.target_account_id}:role/CrossAccountRole"
  }
}
EOF
}

terraform {
  source = "../../terraform-modules/cross-account-resource"
}
```

### Pattern 2: Module Composition

**Use when:** Combining multiple modules in a single configuration

```hcl
# modules/application-stack/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "../../terraform-modules/application-stack"
}

dependency "vpc" {
  config_path = "../networking/vpc"
  mock_outputs = {
    vpc_id     = "vpc-mock"
    subnet_ids = ["subnet-1", "subnet-2"]
  }
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}

dependency "database" {
  config_path = "../data/rds"
  mock_outputs = {
    endpoint = "mock.endpoint.rds.amazonaws.com"
    port     = 5432
  }
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}

dependency "cache" {
  config_path = "../data/elasticache"
  mock_outputs = {
    endpoint = "mock.cache.amazonaws.com"
  }
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}

inputs = {
  name = "my-application"

  # Networking
  vpc_id     = dependency.vpc.outputs.vpc_id
  subnet_ids = dependency.vpc.outputs.private_subnet_ids

  # Database
  database_endpoint = dependency.database.outputs.endpoint
  database_port     = dependency.database.outputs.port

  # Cache
  cache_endpoint = dependency.cache.outputs.endpoint

  # Application configuration
  image_tag      = "latest"
  desired_count  = 2
  cpu            = 256
  memory         = 512
}
```

### Pattern 3: Hooks for Pre/Post Operations

**Use when:** Need to run commands before or after Terraform operations

```hcl
# modules/database/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "tfr:///terraform-aws-modules/rds/aws?version=6.1.0"

  before_hook "backup_check" {
    commands = ["apply"]
    execute  = ["bash", "-c", "echo 'Starting database deployment...'"]
  }

  after_hook "notify_deployment" {
    commands     = ["apply"]
    execute      = ["bash", "-c", "curl -X POST https://slack.webhook.url -d '{\\"text\\":\\"Database deployed\\"}'"]
    run_on_error = false
  }

  error_hook "notify_error" {
    commands = ["apply", "plan"]
    execute  = ["bash", "-c", "echo 'Error occurred during Terraform operation'"]
  }
}
```

### Pattern 4: External Data Integration

**Use when:** Need to fetch dynamic values from external sources

```hcl
# modules/app/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

locals {
  # Fetch current git branch (--quiet suppresses Terragrunt banner output)
  git_branch = run_cmd("--quiet", "git", "rev-parse", "--abbrev-ref", "HEAD")

  # Fetch AWS account ID
  account_id = run_cmd("--quiet", "aws", "sts", "get-caller-identity", "--query", "Account", "--output", "text")

  # Read JSON configuration
  config = jsondecode(file("${get_terragrunt_dir()}/config.json"))
}

terraform {
  source = "../../terraform-modules/app"
}

inputs = {
  git_branch = local.git_branch
  account_id = local.account_id

  app_config = local.config

  name = "${local.config.app_name}-${local.git_branch}"
}
```

## Custom Provider Patterns

### Pattern 1: Kubernetes Provider with EKS

**Use when:** Managing Kubernetes resources with Terragrunt

```hcl
# modules/k8s-app/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

dependency "eks" {
  config_path = "../eks-cluster"

  mock_outputs = {
    cluster_endpoint          = "https://mock-endpoint"
    cluster_certificate       = "mock-cert"
    cluster_name              = "mock-cluster"
  }
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}

generate "kubernetes_provider" {
  path      = "kubernetes_provider.tf"
  if_exists = "overwrite"
  contents  = <<EOF
provider "kubernetes" {
  host                   = "${dependency.eks.outputs.cluster_endpoint}"
  cluster_ca_certificate = base64decode("${dependency.eks.outputs.cluster_certificate}")

  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    args = [
      "eks",
      "get-token",
      "--cluster-name",
      "${dependency.eks.outputs.cluster_name}"
    ]
  }
}

provider "helm" {
  kubernetes {
    host                   = "${dependency.eks.outputs.cluster_endpoint}"
    cluster_ca_certificate = base64decode("${dependency.eks.outputs.cluster_certificate}")

    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      command     = "aws"
      args = [
        "eks",
        "get-token",
        "--cluster-name",
        "${dependency.eks.outputs.cluster_name}"
      ]
    }
  }
}
EOF
}

terraform {
  source = "../../terraform-modules/k8s-app"
}
```

### Pattern 2: Multiple Provider Versions

**Use when:** Different modules require different provider versions

```hcl
# modules/legacy-resource/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

generate "provider_version_override" {
  path      = "versions.tf"
  if_exists = "overwrite"
  contents  = <<EOF
terraform {
  required_version = ">= 1.3.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"  # Legacy version for compatibility
    }
  }
}
EOF
}

terraform {
  source = "../../terraform-modules/legacy-resource"
}
```

## Stacks Patterns (2025)

Terragrunt Stacks allow you to define infrastructure blueprints that generate unit configurations programmatically. GA since v0.78.0 (May 2025).

### Pattern 1: Basic Stack with Units

**Use when:** Creating a reusable infrastructure blueprint

Catalog units expect `values.name` as the base resource identifier from each stack unit.

```hcl
# terragrunt.stack.hcl
loca

---

Source: [Claudary](https://claudary.paisolsolutions.com/skills/common-patterns-1) · https://claudary.paisolsolutions.com
