Skip to content

Active Experiments

The following experiments are available for opt-in. See the experiments overview for how to enable them.


azure-backend

Support for the Azure Storage (azurerm) remote state backend.

azure-backend - What it does

This experiment flag is no longer needed, as the Azure Storage (azurerm) backend is now managed by default.

Terragrunt manages lifecycle operations for the Azure Storage (azurerm) remote state backend, matching what it already does for S3 buckets and GCS buckets:

  1. Bootstrap: creates the resource group (when allowed), storage account, and blob container backing the state, and converges blob versioning and optional soft delete on both new and pre-existing accounts.
  2. Delete: removes state blobs or entire containers, with confirmation prompts.
  3. Migrate: moves state blobs within the same storage account (cross-account migration is refused with guidance to migrate manually).

Authentication supports six methods, resolved in the following order:

  1. SAS token
  2. Storage account access key
  3. Service principal
  4. Managed identity (MSI)
  5. OIDC / workload identity
  6. Azure AD (use_azuread_auth or the default credential chain, which honors az login)

ARM_* and AZURE_* environment variable fallbacks are applied. Set environment (or ARM_ENVIRONMENT) to usgovernment for Azure Government.

Terragrunt reads dependency outputs directly from the Azure state blob without initializing the dependency or running tofu output/terraform output. State protected with customer_provided_key, and configurations that rely on native-only authentication, metadata_host, or timeout_seconds, continue through the native backend path. This preserves the backend’s identity, endpoint, and decryption behavior.

See the Azure Storage backend documentation for configuration keys and known limitations.

azure-backend - How to provide feedback

Now that the azure-backend experiment is complete, please provide feedback in the form of standard GitHub issues.

azure-backend - Criteria for stabilization

To transition the azure-backend feature to a stable release, the following were addressed:

  • internal/azurehelper package wrapping the Azure SDK with a builder pattern matching awshelper/gcphelper.
  • Bootstrap of storage accounts and blob containers, including versioning and soft delete convergence.
  • Optional RBAC role assignment for use_azuread_auth during bootstrap, via assign_blob_data_role.
  • Delete operations for state blobs and containers, with confirmation prompts, and state migration within a storage account.
  • Direct state file reads from Azure blobs for --dependency-fetch-output-from-state.
  • Documentation covering authentication methods, configuration keys, and troubleshooting.
  • End-to-end live coverage against a real subscription for container bootstrap, blob versioning convergence, backend delete, and direct dependency state reads, behind the azure build tag.
  • End-to-end live coverage for resource group and storage account creation, soft-delete retention convergence, and state migration.
  • Community feedback on real-world usage.

base64gzip-compat

Support for the base64gzip_compat HCL function.

This experiment is ongoing and disabled by default. The base64gzip_compat function is not generally available while the experiment runs, and calling it without the experiment enabled returns an error. It becomes generally available once every item in the stabilization criteria below is met.

base64gzip-compat - What it does

When enabled, Terragrunt exposes a base64gzip_compat(str) HCL function that returns the value base64gzip(str) returned in Terragrunt v1.1.3 and earlier, and keeps returning it after Terragrunt 1.2 switches base64gzip() to the current Go encoder.

Use it where the encoded value must stay stable across upgrades, such as an EC2 instance with user_data_base64 and user_data_replace_on_change = true.

Terminal window
terragrunt run --all --experiment base64gzip-compat -- plan

base64gzip-compat - How to provide feedback

Open a GitHub issue describing where you need stable base64gzip() output.

base64gzip-compat - Criteria for stabilization

To transition the base64gzip-compat feature to a stable release, the following must be addressed:

  • Agree on the function name with OpenTofu so both tools expose the same compatibility function.
  • Confirm the output stays byte-identical across Terragrunt and Go releases.

block-iteration

The expansion block, which iterates a dependency, unit, or stack block over a count or for_each, and the enabled attribute on unit and stack blocks.

block-iteration - What it does

This experiment flag is no longer needed, as Terragrunt now accepts an expansion block on dependency, unit, and stack blocks by default. It declares either a count or a for_each, and Terragrunt reads the block it sits in once per element:

terragrunt.stack.hcl
unit "aurora" {
expansion {
for_each = toset(["web", "api"])
}
source = "../units/app"
path = "aurora/${each.key}"
values = {
role = each.key
}
}

That generates two units, at .terragrunt-stack/aurora/web and .terragrunt-stack/aurora/api. You address each element by its key. An expanded dependency is read as dependency.aurora["web"].outputs.id, and terragrunt stack output 'aurora["web"].role' reaches one element of an expanded unit.

unit and stack blocks also accept an enabled attribute. Setting it to false drops the component from stack generation and leaves every other address alone.

See the expansion block reference for the full set of rules, the addressing scheme, and what changing an expansion does to existing state.

block-iteration - How to provide feedback

Now that the block-iteration experiment is complete, please provide feedback in the form of standard GitHub issues.

block-iteration - Criteria for stabilization

To transition the block-iteration feature to a stable release, the following were addressed. Unchecked items remain open.

  • Adding an expansion to a dependency, unit, or stack block, shrinking it, removing it, and setting enabled = false behave as the expansion reference documents for each block type.
  • Growing an expansion adds only the new elements. Adding a for_each key, or appending to the list a count reads, leaves every existing dependency address, generated unit directory, and generated stack tree as it was, and an applied unit keeps its state.
  • Keyed addressing works in inputs and in stack output. stack output reads an address as an HCL traversal, so a key containing a dot stays one segment, and shard[0] reaches the same element as shard["0"].
  • A key containing a quote resolves in inputs when written with HCL’s escape, as in dependency.aurora["a\"b"], and stack output reads the same escaped address.
  • render prints an expanded block as written, followed by its elements as resolved, commented-out blocks. A JSON configuration renders the same way, and --format json emits the block as written.
  • Git-based --filter expressions select the components an expansion orphaned when it shrank. The reference documents that run --all destroy --filter is rejected, that orphans are found only when the stack file or a file it reads appears in the diff, and that a selecting filter drops them.
  • Positive feedback from users replacing repeated blocks with iteration.

bounded-discovery

Enclose graph traversal for a --filter expression within a directory using an inline (dir) operand, instead of the Git repository root.

bounded-discovery - What it does

Graph-traversing filter expressions reach beyond the working directory. Dependent discovery (...{unit}) requires searching from the working directory of the given component up to the Git repository root (if the unit is within a Git repository). Dependency discovery ({unit}...) requires recursive parsing of dependencies to find the terminal dependency. Either way, Terragrunt has to read and parse every configuration it touches along the way for accuracy. In monorepos where sibling environments cannot be parsed independently of each other, that traversal fails or wastes work reaching into them.

This experiment flag is no longer needed, as Terragrunt now accepts an inline (dir) boundary operand by default. It sits in the same operand slot as a traversal depth (e.g. 1...{vpc}):

Terminal window
cd environments/staging
terragrunt find --filter '(.)...{vpc}'
# dependents of vpc, enclosed within the current environment
(.)...{vpc}
# dependencies of vpc, enclosed within the current environment
{vpc}...(.)
# independent bounds per direction
(../shared)...{vpc}...(.)

Any configuration that is discovered outside the boundary, whether a dependent or a dependency, is not read, parsed, or returned. The boundary must be an existing directory. Relative paths are resolved against the working directory, and a dependent-direction boundary must contain the working directory.

A boundary bounds discovery traversal rather than filtering results, so an in-boundary unit reachable only by passing through an out-of-boundary unit is intentionally excluded. Given a —> b —> c, if b is outside the boundary, traversal from a cannot reach c, and vice-versa.

Because the boundary operand claims ( and ), those characters are not read as part of a unit name or path. Wrap a name or path that contains them in braces (e.g. {./weird(name)}) to keep it literal.

The --discovery-boundary flag (env: TG_DISCOVERY_BOUNDARY) is also available by default. It applies one boundary to every --filter expression on the command, in both directions:

Terminal window
cd environments/staging
terragrunt find --filter '...{vpc}' --discovery-boundary .

An inline (dir) operand overrides the flag for the expression that carries it. See the --discovery-boundary reference for how the boundary is resolved.

bounded-discovery - How to provide feedback

Now that the bounded-discovery experiment is complete, please provide feedback in the form of standard GitHub issues.

bounded-discovery - Criteria for stabilization

Criteria for moving bounded-discovery to a stable release:

  • A single directory boundary covers per-environment directories, including units that include a shared parent configuration above the boundary and units that depend on components outside it.
  • A boundary is a directory. Terragrunt does not expand a glob in the operand or the flag.
  • Path-restricting filter intersections (e.g. ...{unit} | ./**) do not narrow the boundary. Set one with a (dir) operand or --discovery-boundary.
  • Decide whether and how the boundary should apply to Git-based filter expressions (e.g. [main...HEAD]).
  • Positive feedback from users relying on the operand and the flag in repositories with isolated environments.

browse-tui

Adds the terragrunt browse command, which browses the discovered infrastructure estate in an interactive terminal user interface (TUI).

browse-tui - What it does

With the experiment enabled, terragrunt browse opens a yazi-style, three-column browser of the discovered estate. See the browse command documentation for usage and keybindings.

Running terragrunt browse without the experiment enabled is an error.

browse-tui - How to provide feedback

Provide your feedback on the browse-tui GitHub Discussion.

browse-tui - Criteria for stabilization

To transition the browse-tui feature to a stable release, the following must be addressed:

  • The browser renders large estates without noticeable latency.
  • Actions for running commands against a highlighted unit or stack are implemented.
  • The same TUI is shared with the catalog scaffolding experience.
  • Positive feedback from users browsing real infrastructure estates.
  • Integration tests covering the core browsing workflow.

catalog-format

Non-interactive output formats for the catalog command.

catalog-format - What it does

This experiment flag is no longer needed, as the catalog command now accepts a --format flag by default. It writes what the catalog discovers to standard output in place of the terminal user interface: jsonl emits one JSON object per catalog entry, and md emits a Markdown document.

Terminal window
terragrunt catalog --format=jsonl | jq -c '{kind, title, component_source}'
terragrunt catalog --format=md > catalog.md

Both formats render progressively, as entries are discovered, so a consumer that only needs the first few can stop reading before discovery finishes. Entries appear in discovery order, which is not stable between runs.

The jsonl records follow a published JSON schema, so consumers can validate what they read.

Without --format, the command opens the terminal user interface when standard input and standard output are both terminals, and writes jsonl otherwise. Scaffolding a module and copying a unit or stack stay in the terminal user interface.

See Non-interactive catalog for each format and the structure of an entry.

catalog-format - How to provide feedback

Now that the catalog-format experiment is complete, please provide feedback in the form of standard GitHub issues.

catalog-format - Criteria for stabilization

Criteria for moving catalog-format to a stable release:

  • A --format flag on catalog accepting jsonl and md.
  • Progressive rendering of both formats, so output is usable before discovery completes.
  • A published JSON schema for jsonl records.
  • A default format derived from what the output stream supports, so piping catalog does not require passing --format.
  • Documentation covering each format and the stability guarantees of the record structure.
  • Integration test coverage for each format.
  • Community feedback on real-world usage.

deep-merge

Support for the deep_merge HCL function.

deep-merge - What it does

When enabled, Terragrunt exposes a deep_merge(map1, map2, ...) HCL function for combining map or object values.

For overlapping keys, values from later arguments override earlier arguments. Nested maps are merged recursively, lists are appended, and null arguments are ignored.

This is useful when building inputs from multiple JSON, YAML, or HCL-derived maps without having to rely on include block merge behavior.

Terminal window
terragrunt run --all --experiment deep-merge -- plan

deep-merge - How to provide feedback

Provide your feedback in the deep-merge GitHub Discussion.

deep-merge - Criteria for stabilization

To transition the deep-merge feature to a stable release, the following must be addressed:

  • Confirm the merge semantics are useful for common configuration layering workflows.
  • Confirm type handling for decoded JSON/YAML and native HCL objects matches user expectations.
  • Positive feedback from users relying on the function in production pipelines.

dependency-fetch-output-from-state

Reading dependency outputs directly from state files.

dependency-fetch-output-from-state - What it does

This experiment flag is no longer needed, as Terragrunt now reads dependency outputs directly from the remote state file by default. That skips initializing the dependency unit, which previously required running tofu output or terraform output against it.

To opt-out of this behavior, pass --no-dependency-fetch-output-from-state (env: TG_NO_DEPENDENCY_FETCH_OUTPUT_FROM_STATE).

Current Backend Support:

  • S3 and GCS backends: Direct state reads are supported
  • Azure Storage (azurerm) backend: Direct state reads are supported when the azure-backend experiment is also enabled
  • Other backends: Falls back to the normal method (using tofu/terraform output)

Azure state protected with customer_provided_key, and Azure configurations that rely on native-only authentication, metadata_host, or timeout_seconds, also use the normal method.

GCS configurations that rely on backend-only credential environment variables, inline credentials or relative credential-file paths, the impersonate_service_account setting, custom storage endpoints, custom universe domains, or competing credential sources with different precedence also use the normal method. This preserves the native backend’s authentication and endpoint behavior.

The credentials backend setting is a local path to a Google Cloud credentials file in JSON format. GOOGLE_APPLICATION_CREDENTIALS points to the same kind of file. Neither is the same thing as access_token, which is a temporary OAuth 2.0 access token used as-is rather than a file.

Terragrunt reads credentials files of type service_account, authorized_user, and external_account (Workload Identity Federation) directly. An external_account file is read directly only when its credential_source is a url or a file with an absolute path. Any other source uses the normal method, because a direct read would resolve it with Terragrunt’s own environment and working directory rather than the unit’s:

  • executable would run the command with Terragrunt’s environment.
  • AWS (an environment_id such as aws1) would use Terragrunt’s AWS credentials.
  • file with a relative path would resolve against Terragrunt’s working directory.

Failure handling:

Reading state directly is an optimization. Outside render and render-json, Terragrunt retries a failed direct read with tofu output or terraform output, unless the state object is missing. If native output retrieval succeeds, only the speedup is lost. For missing outputs, Terragrunt uses configured mock_outputs only when they are allowed for the original command. skip_outputs skips output retrieval and returns eligible configured mocks. The render commands retain their tolerant behavior and can use configured mocks regardless of the command allow-list.

OpenTofu state encryption:

The direct reader cannot decrypt state protected by OpenTofu’s client-side state encryption because it does not evaluate OpenTofu’s encryption configuration or key providers from the remote_state.encryption map. Outside render and render-json, Terragrunt recognizes the encrypted envelope and retries with tofu output or terraform output, allowing the configured binary to decrypt the state when it supports that encryption. If native output retrieval succeeds, only the speedup is lost. For missing outputs, Terragrunt uses configured mock_outputs only when they are allowed for the original command. skip_outputs skips output retrieval and returns eligible configured mocks. The render commands retain their tolerant behavior and can use configured mocks regardless of the command allow-list. Disable the experiment when a render command must resolve real outputs from encrypted state.

Disabling the feature:

Pass --no-dependency-fetch-output-from-state to read outputs through tofu output or terraform output instead:

Terminal window
terragrunt run --all --no-dependency-fetch-output-from-state -- plan

dependency-fetch-output-from-state - How to provide feedback

Now that the dependency-fetch-output-from-state experiment is complete, please provide feedback in the form of standard GitHub issues.

dependency-fetch-output-from-state - Criteria for stabilization

To transition the dependency-fetch-output-from-state feature to a stable release, the following were addressed:

  • Add support for additional backends (GCS and Azure Storage)
  • Live direct-state-read integration coverage for S3, GCS, and Azure Storage
  • Comprehensive integration testing across backend authentication, encryption, workspace, and error scenarios
  • Performance benchmarking to validate speed improvements
  • Error handling and edge case testing
  • Documentation of supported backends and limitations
  • Handle OpenTofu state encryption gracefully (fallback or explicit error message)
  • Community feedback on real-world usage

hook-context-env

Expose additional TG_CTX_* environment variables to hook scripts.

hook-context-env - What it does

When enabled, Terragrunt sets three additional environment variables on the process running every before_hook, after_hook, and error_hook:

  • TG_CTX_HOOK_TYPE — before_hook, after_hook, or error_hook, depending on which lifecycle phase is executing the hook.
  • TG_CTX_SOURCE — the resolved terraform source URL for the current unit, matching the precedence Terragrunt uses for the actual download: the --source CLI override if set, otherwise the evaluated terraform.source (with --source-map applied), otherwise ..
  • TG_CTX_TERRAGRUNT_DIR — the directory containing the current Terragrunt config (equivalent to get_terragrunt_dir()).

These variables make it easier for hook scripts to branch on lifecycle phase, to know whether the unit pulls remote source, and to locate the config directory without having to thread that information through hook arguments.

Terminal window
terragrunt run --all --experiment hook-context-env -- apply

Example hook script:

#!/usr/bin/env bash
case "$TG_CTX_HOOK_TYPE" in
before_hook) echo "preparing $TG_CTX_TERRAGRUNT_DIR" ;;
after_hook) echo "cleaning up $TG_CTX_TERRAGRUNT_DIR" ;;
error_hook) echo "failure in $TG_CTX_TERRAGRUNT_DIR" ;;
esac
if [ "$TG_CTX_SOURCE" != "." ]; then
echo "unit uses source: $TG_CTX_SOURCE"
fi

hook-context-env - How to provide feedback

Provide your feedback in the hook-context-env GitHub Discussion.

hook-context-env - Criteria for stabilization

To transition the hook-context-env feature to a stable release, the following must be addressed:

  • Confirm the three new variables cover the most common hook scripting needs.
  • Confirm the chosen variable names and values (before_hook/after_hook/error_hook) match user expectations.
  • Positive feedback from users relying on the variables in production hook scripts.

iac-engine

Support for Terragrunt IaC engines.

iac-engine - What it does

Enables usage of Terragrunt IaC engines for running IaC operations. This allows Terragrunt to use pluggable engines to execute OpenTofu/Terraform commands, providing enhanced functionality and extensibility.

IaC engines are still experimental, as the API is unstable and may change in future minor versions of Terragrunt.

You can disable engine usage on a per-command basis using the --no-engine flag, even when the experiment is enabled globally.

iac-engine - How to provide feedback

Provide your feedback on the Terragrunt IaC Engines GitHub discussion.

iac-engine - Criteria for stabilization

To transition the iac-engine feature to a stable release, the following must be addressed, at a minimum:

  • API stability and backward compatibility guarantees
  • Comprehensive integration testing across all supported operations
  • Documentation of engine development and integration process
  • Performance benchmarks and optimization
  • Security review of engine execution and isolation mechanisms
  • Community feedback on real-world usage and edge cases

mutable-generate

Deduplication of the files produced by generate blocks through content-addressable storage, with a mutable attribute to opt out.

mutable-generate - What it does

This experiment flag is no longer needed, as Terragrunt stores the contents a generate block produces in the CAS by default. The file written at path is a read-only link to that stored copy. The link is read-only because the stored copy is shared: an edit through one path would change what every later reader of that content sees.

Because the stored copy is addressed by the hash of its contents, anything generating identical contents links to the same copy instead of writing its own. A generate block declared in a parent configuration writes the same content into every unit that includes it, so a provider block shared across a few hundred units is stored once.

The generate block accepts a mutable attribute for cases where a shared read-only file does not work:

generate "provider" {
path = "provider.tf"
if_exists = "overwrite"
mutable = true
contents = <<EOF
provider "aws" {
region = "us-east-1"
}
EOF
}

mutable = true gives the block a writable file of its own. Use it when something writes to the generated file, such as a hook that patches it before tofu/terraform runs. Terragrunt regenerates the file on every run, and tofu/terraform only read it, so most generate blocks do not need it.

--no-cas writes generated files directly, and mutable has no effect. The backend file generated by a remote_state block is always written directly.

See the generate block reference for every attribute the block accepts.

mutable-generate - How to provide feedback

Now that the mutable-generate experiment is complete, please provide feedback in the form of standard GitHub issues.

mutable-generate - Criteria for stabilization

Criteria for moving mutable-generate to a stable release:

  • A mutable attribute on the generate block, parsed from both the block and attribute forms.
  • Deduplication of non-mutable generated files through the CAS store, materialized as read-only hard links.
  • Confirmation that read-only generated files break no established workflow, including hooks and IaC engines.
  • remote_state.generate stays out of the CAS and writes its backend file directly into each unit.
  • Community feedback on the disk savings actually observed at scale.

oci

Support for downloading modules from OCI Distribution registries using oci:// sources.

oci - What it does

This experiment flag is no longer needed, as oci:// sources are now supported by default.

OpenTofu 1.10 can download modules from an OCI Distribution registry using an oci:// source. Terragrunt supports the same sources natively, so a single source string works the same way in both tofu and Terragrunt against registries such as Amazon ECR, GitHub Container Registry, Azure Container Registry, Google Artifact Registry, and self-hosted or air-gapped registries.

Terragrunt accepts oci:// source URLs in terraform { source = "..." } blocks, and in the unit and stack blocks of a terragrunt.stack.hcl. For example:

terraform {
source = "oci://ghcr.io/acme/terraform-modules/vpc?tag=1.0.0"
}
unit "vpc" {
source = "oci://ghcr.io/acme/terragrunt-units/vpc?tag=1.0.0"
path = "vpc"
}

Specify either tag or digest; omitting both selects the latest tag. //subdir selectors are supported.

Credentials come from OpenTofu’s CLI config, in the oci_credentials and oci_default_credentials blocks. Terragrunt reads the file named by TF_CLI_CONFIG_FILE or TERRAFORM_CONFIG, otherwise the first of ~/.tofurc and ~/.terraformrc that exists (on Windows, %APPDATA%\tofu.rc and %APPDATA%\terraform.rc). Unless one of those environment variables is set, it also merges the *.tfrc and *.tfrc.json files in OpenTofu’s config directory. Terragrunt also reads ambient Docker and containers auth files (~/.docker/config.json and containers auth.json), following the containers-auth search order OpenTofu uses as of OpenTofu 1.12. Set docker_style_config_files in oci_default_credentials to replace those default search paths, or an empty list to disable ambient discovery entirely.

Terragrunt ranks every matching CLI-config and ambient credential together by how much of the repository path each one matches, and uses the single best match. A CLI-config entry wins only when both candidates match equally closely. The oci_default_credentials helper is the global fallback, and Terragrunt pulls anonymously when nothing matches. Set discover_ambient_credentials = false in the oci_default_credentials block to use CLI config only.

Credential helpers configured in either place (credHelpers and credsStore in the Docker config, or a block’s docker_credentials_helper, such as ecr-login) are invoked when selected as the credential source, so ECR and other helper-backed registries work without a baked-in login.

oci - How to provide feedback

Track and discuss this experiment in gruntwork-io/terragrunt#4555. When reporting issues or providing feedback, please include:

  • The registry you are using (ECR, GHCR, ACR, GAR, self-hosted).
  • The authentication method (an OpenTofu CLI-config oci_credentials block, ambient Docker config, or a credential helper such as ecr-login), and the CLI config file in use.
  • The full oci:// source string, and whether you pin by tag or digest.
  • Any errors encountered during module download.

oci - Criteria for stabilization

To transition the oci feature to a stable release, the following were completed:

  • A getter that resolves oci:// sources, selecting the application/vnd.opentofu.modulepkg artifact and its archive/zip layer, with blob digest verification.
  • OpenTofu CLI-config and ambient Docker-config credential discovery matching OpenTofu’s search order.
  • Credential-helper support (docker-credential-*, ecr-login) so ECR and other helper-backed registries work through the configured helper.
  • Content-addressable caching keyed on the resolved manifest digest, with correct re-resolution of mutable tags.
  • A portability guarantee that one source string produces an identical module via tofu and Terragrunt.
  • Documentation covering the source syntax, authentication tiers, and publishing contract.
  • Integration test coverage driving the full download chain against a local OCI Distribution registry.
  • Gated CI coverage against hosted registries (GHCR, ECR) with real credentials.
  • Community feedback on real-world usage.

offline-cas

Control over the probe cache the CAS keeps, including resolving a run without contacting any remote.

offline-cas - What it does

This experiment turns on the probe cache. The CAS records the answer to each cheap probe it makes, for every source it probes, so a later run can learn what a source resolves to without querying the remote again. An answer for a source pinned to a specific revision is served for 24 hours; anything that can change upstream is probed again on every run.

Three flags come with it and change how the recorded answers are used:

  • --cas-offline never contacts a remote. Every source is answered from its recorded probe, however old, and linked from the local store. A source with no recorded answer, or whose content the store lacks, fails with an error naming it instead of being fetched.
  • --cas-refresh ignores the recorded answers for one run and asks every remote again, then records what it learns. Use it when a version tag has moved and the 24 hour window for pinned sources has not passed.
  • --cas-probe-ttl trusts a recorded probe of a source that can change upstream for a chosen duration, such as 10m, rather than probing it on every run.
Terminal window
terragrunt run --experiment offline-cas --all --cas-offline -- plan

The flags are available on the same commands as --no-cas. --cas-offline and --cas-refresh cannot be combined. A source with no cheap probe, such as an SMB share, has no answer to record and is fetched on every run. With the experiment off, nothing is recorded or served and every run probes every source.

offline-cas - How to enable it

Terminal window
# Via CLI flag
terragrunt run --experiment offline-cas --all --cas-probe-ttl 10m -- plan
# Via environment variable
export TG_EXPERIMENT=offline-cas
terragrunt run --all --cas-probe-ttl 10m -- plan

Setting one of the three flags without the experiment returns an error naming the flag.

offline-cas - Criteria for stabilization

To transition the offline-cas feature to a stable release, the following must be addressed, at a minimum:

  • Confirm an offline run reports every unresolvable source in one pass, rather than failing on the first one.
  • Decide whether the sources with no cheap probe (SMB shares) should be resolvable offline, or whether failing on them is right.
  • Decide whether a warm store should be reachable without a prior online run, such as through a store that can be built and shipped to an air-gapped host.
  • Decide whether the 24 hour window for pinned sources belongs under --cas-probe-ttl or stays separate.
  • Decide how the store is pruned, covering recorded answers and the much larger content beside them, so a long-lived store does not keep growing on sources that are gone. Marking an answer as used when it is served, so that age since last use drives eviction rather than age since recording, is the likely mechanism.
  • Community feedback from air-gapped and high-unit-count runs on whether the three flags cover their needs.

optional-dependency-outputs

Support for skipping all dependency output resolution during a run.

optional-dependency-outputs - What it does

This experiment flag is no longer needed, as the --no-dependency-outputs flag (env: TG_NO_DEPENDENCY_OUTPUTS) is now available by default. It skips output resolution for every dependency block in the run, so Terragrunt does not call tofu output on dependencies. The effect matches setting skip_outputs = true on each dependency block.

Terminal window
terragrunt run --no-dependency-outputs -- init
terragrunt run --all validate --no-dependency-outputs

Use it for commands that do not need dependency outputs, such as init or validate, or when dependencies have not been applied yet.

See the --no-dependency-outputs reference for how the flag treats mock_outputs.

optional-dependency-outputs - How to provide feedback

Now that the optional-dependency-outputs experiment is complete, please provide feedback in the form of standard GitHub issues.

optional-dependency-outputs - Criteria for stabilization

Criteria for moving optional-dependency-outputs to a stable release:

  • Validate behavior with single-unit and queue-based runs.
  • Gather community feedback on the flag name and scope.
  • Confirm the interaction with commands that require dependency outputs (such as plan, apply, or destroy).

optional-hooks

Support for disabling Terragrunt hooks during run.

optional-hooks - What it does

This experiment flag is no longer needed, as the --no-hooks flag (env: TG_NO_HOOKS) is now available by default. It skips every before_hook, after_hook, and error_hook block in the run, including run --all.

Terminal window
terragrunt run --no-hooks -- plan
terragrunt run --all --no-hooks -- plan

Use it to bypass hook automation temporarily, e.g. when debugging a faulty hook or OpenTofu/Terraform module.

optional-hooks - How to provide feedback

Now that the optional-hooks experiment is complete, please provide feedback in the form of standard GitHub issues.

optional-hooks - Criteria for stabilization

Criteria for moving optional-hooks to a stable release:

  • Validate behavior with single-unit and queue-based runs.
  • Gather community feedback on whether all hook types should be skipped.
  • Confirm the flag name leaves room for more granular hook controls in the future.

otel-logs

Export Terragrunt’s logs as an OpenTelemetry logs signal.

otel-logs - What it does

When enabled, Terragrunt emits its log output as OpenTelemetry log records in addition to the existing traces and metrics signals. The exporter is selected with TG_TELEMETRY_LOGS_EXPORTER:

  • none - no log exporting (the default).
  • console - write log records to the console as JSON.
  • otlpHttp - export logs to an OpenTelemetry collector over HTTP.
  • otlpGrpc - export logs to an OpenTelemetry collector over gRPC.

The OTLP exporters read their endpoint from the standard OTEL_EXPORTER_OTLP_ENDPOINT environment variable. Set TG_TELEMETRY_LOGS_EXPORTER_INSECURE_ENDPOINT=true to disable TLS and send logs over an insecure connection. Only use this for local collection.

Terminal window
TG_TELEMETRY_LOGS_EXPORTER=otlpHttp terragrunt run --all --experiment otel-logs -- apply

Records emitted while a unit’s span is active carry that span’s trace and span IDs, so a failed unit’s logs link back to its span in the backend: clicking a unit’s span in the trace view surfaces exactly the logs it produced. Run-level records emitted outside any span are exported without correlation IDs. Without the experiment enabled, the logs exporter stays inert regardless of TG_TELEMETRY_LOGS_EXPORTER.

otel-logs - How to provide feedback

Provide your feedback in the OpenTelemetry logs integration issue.

otel-logs - Criteria for stabilization

To transition the otel-logs feature to a stable release, the following must be addressed:

  • Confirm the exporter types and configuration cover common collector setups.
  • Validate log volume and batching behavior on large stacks.
  • Confirm trace/span correlation is reliable across the run lifecycle, including run-level logs emitted outside a unit span.
  • Settle on the dependency stability story for the OpenTelemetry logs SDK, which is still pre-1.0.

profiling

Collect CPU profiles, memory (heap) profiles, and goroutine profiles for Terragrunt.

profiling - What it does

This experiment flag is no longer needed, as Terragrunt collects runtime profiles by default. Use these CLI flags, or the corresponding TG_PROFILE_* environment variables:

  • --profile-cpu / TG_PROFILE_CPU: write a CPU profile
  • --profile-mem / TG_PROFILE_MEM: write a heap memory profile
  • --profile-goroutine / TG_PROFILE_GOROUTINE: write a goroutine profile (stack traces of all goroutines)
  • --profile-dir / TG_PROFILE_DIR: collect all of the above into a single directory using conventional filenames

Example:

Terminal window
terragrunt --profile-dir /tmp/profiles run --all -- plan

This is primarily intended for performance investigation and debugging of Terragrunt itself.

profiling - How to provide feedback

Now that the profiling experiment is complete, please provide feedback in the form of standard GitHub issues.

profiling - Criteria for stabilization

To transition the profiling feature to a stable release, the following were addressed:

  • Validate that profiling reliably covers Terragrunt runs across different invocation styles.
  • Ensure documentation (CLI flags + env vars) is complete and accurate.
  • Gather feedback on the chosen flag names (--profile-*).
  • Decide whether additional profile types (block, mutex, etc.) should be exposed.
  • Confirm the interaction with --experiment-mode and TG_EXPERIMENT is ergonomic.

slow-task-reporting

Progress reporting for long-running Terragrunt operations.

slow-task-reporting - What it does

When enabled, Terragrunt displays animated progress spinners for operations that take longer than 1 second (e.g., Git worktree creation). Once the operation completes, the spinner is replaced with an INFO log line showing the operation result and elapsed time.

This provides visual feedback during operations that would otherwise show no output:

  • Git worktree creation for --filter with Git references
  • Catalog repository cloning (terragrunt catalog)
  • OpenTofu/Terraform source downloads via go-getter

In non-interactive environments (CI/CD, piped output), spinners are suppressed and INFO log lines are emitted instead. To prevent CI systems (e.g., CircleCI) from killing jobs due to prolonged output silence, periodic keepalive log lines are emitted every 30 seconds while the operation is in progress.

Terminal window
terragrunt run --all --experiment slow-task-reporting -- plan

slow-task-reporting - How to provide feedback

Provide your feedback on the slow-task-reporting GitHub Discussion.

slow-task-reporting - Criteria for stabilization

To transition the slow-task-reporting feature to a stable release, the following must be addressed:

  • Validate spinner rendering across common terminal emulators (iTerm2, Terminal.app, Windows Terminal, GNOME Terminal)
  • Extend progress reporting to additional slow operations (e.g., provider caching)
  • Community feedback on usefulness and threshold tuning
  • Ensure no interference with structured log output when using --log-format json

Support symlink resolution for Terragrunt units.

By default, Terragrunt will ignore symlinks when determining which units it should run. By enabling this experiment, Terragrunt will resolve symlinks and add them to the list of units being run.

It also makes include_in_copy and exclude_from_copy glob patterns rooted at a symlinked directory expand through the link, so the contents of a linked directory are copied into (or excluded from) the OpenTofu/Terraform working directory. A link that points back at a directory already being copied, or at a parent of one, is skipped with a warning.

Provide your feedback on the Experiment: Symlinks discussion.

To stabilize this feature, the following need to be resolved, at a minimum:

  • Ensure that symlink support continues to work for users referencing symlinks in flags. See #3622.
    • Add integration tests for all filesystem flags to confirm support with symlinks (or document the fact that they cannot be supported).
  • Ensure that MacOS integration tests still work. See #3616.
    • Add integration tests for MacOS in CI.

tg-login

Signing in to the Gruntwork Developer Portal from the CLI, so an admin can define a catalog in the portal alongside the one local HCL names.

tg-login - What it does

Nothing yet. The flag is reserved, and no command reads it.

Once the command lands, terragrunt login will sign you in through your browser using the OAuth 2.0 Device Authorization Grant (RFC 8628). The CLI shows a short code, your browser opens to a page where you confirm that code and grant access, and the CLI receives a token scoped to your organization. terragrunt catalog then reads the repositories an admin selected in the portal, so there is no catalog block to write or maintain.

A catalog block in your configuration keeps working whether or not you are signed in.

tg-login - How to enable it

Terminal window
# Via CLI flag
terragrunt --experiment tg-login login
# Via environment variable
export TG_EXPERIMENT=tg-login
terragrunt login

terragrunt login does not exist yet, so both forms currently set a flag that nothing reads.

tg-login - Criteria for stabilization

To transition the tg-login feature to a stable release, the following must be addressed, at a minimum:

  • terragrunt login completes the device flow and reports the signed-in user and organization.
  • On a headless or SSH session, the CLI prints the URL and code to open on another device, and login still completes.
  • The CLI stores the token so it survives between commands and expires on its own.
  • terragrunt catalog browses and scaffolds from the portal-defined catalog as it does from a local one.
  • A user who is not signed in still gets a catalog from local configuration.
  • A user with no catalog configured anywhere gets guidance on setting one up.
  • Test coverage for login and catalog that does not need a live portal.
  • Documentation for login and catalog setup.

version-attribute

Support for a version attribute on the terraform block that resolves a registry module from a version constraint.

version-attribute - What it does

This experiment flag is no longer needed, as the terraform block accepts the version attribute by default. The attribute holds a version constraint for a tfr:// registry module, such as ~> 3.3 or >= 1.0.0, < 2.0.0:

terraform {
source = "tfr://registry.opentofu.org/terraform-aws-modules/vpc/aws"
version = "~> 3.3"
}

On every run, Terragrunt resolves the constraint against the registry’s list-versions endpoint before the download begins, then fetches the highest published version that satisfies it. The syntax matches the version argument on OpenTofu and Terraform module blocks, so the source URL can leave out an exact version.

The constraint lives only in the version attribute. Terragrunt downloads and caches the exact version it resolved, and the --source override accepts an exact pin only.

See the terraform block reference for how the attribute combines with ?version= and --source.

version-attribute - How to provide feedback

Now that the version-attribute experiment is complete, please provide feedback in the form of standard GitHub issues.

version-attribute - Criteria for stabilization

Criteria for moving version-attribute to a stable release:

  • Terragrunt resolves the constraint on every run, so a newly published version that satisfies it is downloaded on the next run without --source-update. The terraform block reference documents this.
  • A prerelease is eligible only when the constraint names one (e.g. >= 1.0.0-rc1), matching OpenTofu and Terraform.
  • --source and TG_SOURCE accept exact pins only, and a constraint there is an error.
  • Community feedback on real-world usage.