Back to Blog
Terragrunt

Terragrunt 1.1 Released!

Yousif Akbar
Yousif
Akbar
,
Principal Software Engineer
July 2, 2026

Terragrunt 1.1 is a release about scale. Across the 1.0 series we shipped a string of experiments aimed at the parts of Terragrunt that can need streamlining as your estate grows: smoothly composing infrastructure out of reusable stacks, avoiding performance penalties from managing a large infrastructure estate, and conveniently leveraging your infrastructure catalog. With 1.1, six experimental features graduate to general availability, unlocking further scale.

Stack Dependencies

This is the one we are most excited about. A Terragrunt stack generates a tree of units from a single terragrunt.stack.hcl file. Wiring one of those units to another one used to mean defining dependency blocks in your catalog with values. variables to dynamically define dependency paths. Stack dependencies let you declare those relationships up front instead.

Add an autoinclude block inside a unit or stack block, and Terragrunt generates partial unit/stack configurations to the side of the generated terragrunt.hcl / terragrunt.stack.hcl file that get automatically merged into the unit/stack definition.

# terragrunt.stack.hcl

unit "vpc" {
  source = "github.com/acme/catalog//units/vpc"
  path   = "vpc"
}

unit "app" {
  source = "github.com/acme/catalog//units/app"
  path   = "app"

  autoinclude {
    dependency "vpc" {
      config_path = unit.vpc.path
    }
    inputs = {
      vpc_id = dependency.vpc.outputs.vpc_id
    }
  }
}

You have the ability to patch unit definitions in your terragrunt.stack.hcl files however you like, and Terragrunt will parse your configuration with the merged configurations. Using the autoinclude block, you can also patch your unit definitions to introduce any other configurations that can be used as part of valid unit configurations.

# terragrunt.stack.hcl

unit "app" {
  source = "github.com/acme/catalog//units/app"
  path   = "app"

  autoinclude {
    errors {
		  retry "transient_errors" {
		    retryable_errors = [".*Error: transient network issue.*"]
		    max_attempts = 3
		    sleep_interval_sec = 5
		  }
    }
  }
}

In addition to being able to patch units with autoinclude, you can also do the same dynamic configuration adjustment of nested stacks defined with the stack block.

# terragrunt.stack.hcl

stack "dev" {
  source = "github.com/acme/catalog//stacks/environment"
  path   = "dev"
}

stack "prod" {
  source = "github.com/acme/catalog//stacks/environment"
  path   = "prod"

  autoinclude {
    unit "security_scanner" {
      source = "github.com/acme/catalog//units/security-scanner"
      path   = "security-scanner"
    }
  }
}

As part of the general availability of the stack-dependencies experiment, you can now also use the include block within stack configurations, and target stacks with dependency blocks.

# terragrunt.stack.hcl

include "environment" {
  path = find_in_parent_folders("environment.stack.hcl")
}

unit "security_scanner" {
  source = "github.com/acme/catalog//units/security-scanner"
  path   = "security-scanner"
}

# terragrunt.stack.hcl

stack "networking" {
  source = "github.com/acme/catalog//stacks/networking"
  path   = "networking"
}

unit "app" {
  source = "github.com/acme/catalog//units/app"
  path   = "app"
  
  autoinclude {
    dependency "networking" {
      config_path = stack.networking.path
    }
    inputs = {
      vpc_id = dependency.networking.outputs.vpc.vpc_id
    }
  }
}

Note that this relationship only goes one way. Units can depend on stacks, but the opposite is not true. Stacks cannot depend on other stacks or units.

Stack dependencies pair naturally with the CAS. More on that below.

Terragrunt Scale customers can expect support out of the box on day one .

This feature is designed to be compatible with how Pipelines detects diffs in generated stacks. Changes driven by autoinclude blocks will automatically get picked up by Pipelines, running GitOps workflows against the components needing runs.

Content Addressable Store (CAS)

The Content Addressable Store (CAS) saves Terragrunt from downloading the same source twice. It addresses source code by their content in a central store, and regenerates source code from that local store instead of repeating the fetch.

With 1.1, the CAS reaches well past support for Git. It now also de-duplicates fetches to HTTP, S3, GCS, and Mercurial sources, along with OpenTofu and Terraform registry sources via tfr:// prefixed sources. It caches modules, and unit and stack configurations alike.

# CAS is on by default in 1.1
terragrunt run --all -- plan

# Opt out for a single invocation
terragrunt run --all --no-cas -- plan

Two block attributes give you finer control, and both default to off.

update_source_with_cas

This makes a generated stack self-contained. With it set, Terragrunt rewrites a relative source into a content-addressed cas:: reference at generation time, so the generated tree no longer depends on the surrounding repository layout. This lets catalog authors keep relative paths in their sources and still ship a portable, reproducible stack.

You author the stack with an ordinary relative path:

# stacks/networking/terragrunt.stack.hcl
unit "vpc" {
  source = "../..//units/vpc" # Here, `vpc` is a unit defined in your catalog
  path   = "vpc"

  update_source_with_cas = true
}

After terragrunt stack generate, the relative path is replaced by a reference to the exact tree CAS stored:

# generated output, after terragrunt stack generate
unit "vpc" {
  source = "cas::sha1:f39ea0ebf891c9954c89d07b73b487ff938ef08b"
  path   = "vpc"

  update_source_with_cas = true
}

Where cas:: is a special forced-getter protocol used by Terragrunt to point at the stored unit source in your local CAS.

The same attribute works in the terraform block of a unit, where it rewrites the module source the unit points at. Here the //subdir matters: Terragrunt preserves it on the rewritten reference, so a source that selects a sub-directory keeps resolving to that same sub-directory inside the content-addressed tree, with the context of the rest of the repository for relative sub-module references.

# units/vpc/terragrunt.hcl
terraform {
  source = "../..//modules/vpc"

  update_source_with_cas = true
}

After generation, the //modules/vpc tail is carried over onto the cas:: reference, so relative references into the module tree keep working:

# generated output, after terragrunt stack generate
terraform {
  source = "cas::sha1:f39ea0ebf891c9954c89d07b73b487ff938ef08b//modules/vpc"

  update_source_with_cas = true
}

Terragrunt Scale customers get a performance boost out of this.

Prior to this change, you had to propagate references to source versions through values if you wanted versions of sources in child units/stacks to be defined dynamically. Given that Pipelines detects such changes on the filesystem of terragrunt.values.hcl files as units/stacks that need plan/apply operations run against them, switching to a deterministic value for the source attribute generated from the contents of the CAS significantly reduces unnecessary plans and applies.

mutable

This controls how CAS places fetched content on disk, and it is set on the terraform block of a unit. By default, CAS hardlinks blobs from its shared store into your working tree, which is fast and uses no extra space, but it means that editing those files in place would corrupt the store. To avoid this, Terragrunt sets the write permissions of the files hardlinked into the .terragrunt-cache directory such that they are read-only.

Set mutable = true and Terragrunt will copy the content into .terragrunt-cache instead, making the tree safe to edit at the cost of a little extra I/O and loss of disk space.

# units/vpc/terragrunt.hcl
terraform {
  source = "github.com/acme/catalog//modules/vpc"

  mutable = true
}

CAS is on by default as of 1.1. If you ever need to bypass it for a run, you can use --no-cas to disable it for that run.

Catalog adds support for units, stacks, templates

terragrunt catalog got a ground-up redesign. It launches instantly with no configuration and discovers components across repositories defined as your catalog in the background, streaming them into the TUI as it finds them.

Modules no longer have to live under a modules/ directory; they can be defined anywhere in your catalog. To give you more control over what the catalog command discovers from your catalogs, a .terragrunt-catalog-ignore file can be defined in your catalog with .gitignore-style globs to filter out components you don’t want discovered.

Components displayed in the catalog now have metadata enrichment to help you better navigate your catalog. On each component, you’ll see a kind label (template, stack, unit or module), and optional tags defined using README.md front-matter of a given component.

You now also have access to a new TUI screen for interactively populating the values used when scaffolding a component from your catalog using the s button on the component selection screen.

Run exactly what a change touches

Terragrunt can already select units by the files they read, which is the foundation of change-based runs in CI. The gap was local modules: pointing a unit's terraform { source = ... } at a local directory did not mark the files inside that directory as read, so a change to the module would not select the unit.

When a unit's source is a local module, Terragrunt now walks the directory and records every *.tf, *.tofu, and *.hcl file (and their .json variants) as read for that unit, skipping non-source files like README.md files. It also adds a mark_glob_as_read(pattern) HCL function that marks every file matching a glob and returns the matched paths.

# In HCL: mark_glob_as_read("./shared/**/*.tf")
terragrunt run --all --filter 'reading=./shared/network.tf' -- plan

The effect is precise CI targeting: change a shared module or a globbed config file, and a reading= filter selects exactly the units that consume it. To upgrade, drop --experiment mark-many-as-read.

Terragrunt Scale customers have already used this functionality on an experimental, opt-in basis.

The net effect is that Pipelines will automatically run plans and applies for units that are impacted by changes to referenced module content in the same repository.

Skip auth where you do not need it

By default, Terragrunt runs your --auth-provider-cmd once for every unit it discovers, so HCL functions that need credentials resolve correctly during parsing. On a large estate that auth cost is paid hundreds of times before a single unit runs, and it can dominate wall-clock time on change-based runs.

Opt-out auth gives you a way to skip it during discovery. The --no-discovery-auth-provider-cmd flag (env TG_NO_DISCOVERY_AUTH_PROVIDER_CMD) turns off discovery-phase auth while still executing it normally for the units that actually run.

terragrunt run --all \
  --no-discovery-auth-provider-cmd \
  --queue-include-units-reading=./changed-file.txt \
  plan

Use this only when you know parsing resolves without credentials.

Terragrunt Scale customers have already used this functionality on an experimental, opt-in basis.

The net effect is that Pipelines will run Terragrunt far faster for power users that are able to explicitly confirm that they aren’t affected by the side-effect of losing calls to the auth provider command during discovery.

See the queue as a tree

Before a run --all, Terragrunt prints the units it is about to run. A flat list hides the shape of a large dependency graph, so in 1.1 the queue renders as a dependency tree by default. The run order and the relationships between units are clear before anything executes. The header adapts to direction: dependencies before dependents on apply, the reverse on destroy.

The following units will be run, starting with dependencies and then their dependents:
.
├── monitoring
╰── vpc
    ╰── database
        ╰── backend-app

Still cooking

Six experiments graduated, but the experiment track keeps moving. A few worth trying, each enabled with --experiment :

  • deep-merge adds a deep_merge(map1, map2, ...) HCL function. Maps and objects merge recursively, lists append, and later arguments win.
  • slow-task-reporting shows progress spinners for operations that run longer than a second, such as source downloads, Git worktree creation, and catalog clones. Falls back to periodic log lines in non-interactive runs.
  • symlinks adds symlink resolution for units.
  • dependency-fetch-output-from-state reads dependency outputs straight from S3 state, falling back to tofu output on other backends.
  • azure-backend adds support for native azurerm backend support. It has no behavioral effect yet; follow #4307 for progress.

If you try any of these, the discussion threads linked from the docs are how you can share your feedback to encourage prioritization and graduation to general availability.

Upgrading

To upgrade to Terragrunt 1.1, follow the instructions in the install docs, or run the following:

curl -sSfL --proto '=https' --tlsv1.2 https://terragrunt.com/install | bash

If you were manually setting any of the following experiments, you no longer need to set them:

  • stack-dependencies
  • cas
  • catalog-redesign
  • mark-many-as-read
  • dag-queue-display
  • opt-out-auth

Thank you to everyone who ran these experiments early and filed the feedback that got them here.