github gruntwork-io/terragrunt v1.0.6

4 hours ago

๐Ÿ› Bug Fixes

terragrunt no longer hangs when download_dir is a non-hidden subdirectory of the unit

Setting download_dir (via the attribute, --download-dir, or TG_DOWNLOAD_DIR) to a subdirectory of the unit's working directory whose name did not start with a dot caused commands that prepare the OpenTofu or Terraform source (apply, plan, run, and similar) to hang.

For example:

# /infra/web/terragrunt.hcl
download_dir = "cache"

terraform {
  source = "./mod"
}

Here terragrunt apply would copy ./mod into cache/, see the new cache/ directory on the next read of the unit, and recurse into it. The default .terragrunt-cache was unaffected because Terragrunt's source-copy step skips any directory whose name starts with a dot.

These configurations now produce an immediate error identifying the source and destination paths.

mark-many-as-read experiment now triggers during discovery

With the mark-many-as-read experiment enabled, a unit whose terraform { source = ... } pointed at a local module did not show up under --filter 'reading=' filters that referenced files inside that module. Discovery would parse the unit, but the module files were never recorded as read, so the reading filter attribute could not match and the queue came back empty.

The module walk now runs on the discovery code path as well, so changes to files in a local module source flow through to the units that depend on them.

terragrunt render no longer crashes on exclude or catalog blocks with certain attributes

Rendering a config crashed with a value has no attribute of that name panic before any output could be produced when:

  • the exclude block set no_run, or
  • the catalog block set default_template, no_shell, or no_hooks.

These attributes are now carried through the render pipeline alongside the other fields on their respective blocks, so both blocks round-trip cleanly.

terragrunt render no longer crashes on multiple errors.ignore blocks with mismatched signals

Rendering a config that defined more than one errors.ignore block crashed with an inconsistent list element types panic when the signals map was populated on one block and absent (or differently typed) on another. The same crash showed up in dependency-output evaluation, since both paths build the same rendered representation of the config.

Each ignore block is now rendered with a uniform shape. Indexed access (errors.ignore[0]), length, and iteration still work, and the signals map on each block is preserved as written.

Suppress spurious Unknown variable: dependency errors during dependency resolution

terragrunt plan and apply no longer print ERROR Error: Unknown variable "dependency" lines when a unit pulls in a shared include (e.g. via find_in_parent_folders) that references dependency.* outputs. The plans completed correctly, but the error lines cluttered CI logs.

Resolves #6036.

terragrunt stack commands no longer crash on stacks with multiple units

Running terragrunt stack output (or any command that resolves concurrently parsing multiple configuration files) against a stack with several units could intermittently crash while the units were being parsed in parallel due to a race on internal bookkeeping of files read (used in the reading filter attribute).

Parallel unit parsing now coordinates safely when recording which source files were read, preventing crashes.

terraform_binary properly respected when both tofu and terraform are on PATH

A regression in command execution caching resulted in over-caching the STDOUT result of tofu --version when both tofu and terraform were available on PATH and terraform_binary was set. Early on in the execution flow, Terragrunt checks if OpenTofu is installed what its version is to determine if it supports setting of the automatic provider cache directory. This resulted in the value of terraform_binary being ignored for later version checks to assess compliance with terraform_version_constraint.

The version-detection cache used per run is now scoped to the binary that produced each entry, so the version recorded against an early default-binary resolution no longer leaks into the later resolution that honors terraform_binary.

๐Ÿงช Experiments Added

deep-merge experiment adds a deep_merge HCL function

Enable the new deep-merge experiment to use the deep_merge(map1, map2, ...) HCL function.

deep_merge recursively merges map and object values. Later arguments override earlier arguments for overlapping keys, nested maps are merged recursively, lists are appended, and null arguments are ignored.

This is useful when composing inputs from multiple decoded JSON, YAML, or HCL-derived maps:

locals {
  config_json_files = sort(fileset(get_terragrunt_dir(), "*.json"))
  config = deep_merge([
    for file in local.config_json_files :
    jsondecode(file("${get_terragrunt_dir()}/${file}"))
  ]...)
}

inputs = local.config

Calling deep_merge without enabling the deep-merge experiment returns an error.

opt-out-auth โ€” Opt out of --auth-provider-cmd during discovery

Enable the new opt-out-auth experiment to use --no-discovery-auth-provider-cmd (env: TG_NO_DISCOVERY_AUTH_PROVIDER_CMD), which disables the auth provider command during the discovery phase.

Without the flag, Terragrunt assumes that --auth-provider-cmd must be run per parsed component during the discovery phase so that it can reliably resolve HCL functions such as get_aws_account_id and run_cmd. On large repositories with run --all --filter='reading=', this dominates wall-clock time because the auth command runs for every discovered unit rather than only the subset that will run.

The --no-discovery-auth-provider-cmd flag turns off auth invocations during discovery. The auth provider command still runs normally when running units.

Units whose discovery-relevant blocks depend on credentials produced by --auth-provider-cmd will fail to parse with the flag set. Use it when you know that parsing will resolve successfully without any authentication done beforehand by Terragrunt.

While this flag is experimental, you must also opt-in to the opt-out-auth experiment by setting the TG_EXPERIMENT environment variable to opt-out-auth or by passing the --experiment=opt-out-auth flag to terragrunt run. This flag might experience breaking changes based on community feedback for the duration of the experiment.

e.g.

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

๐Ÿงช Experiments Updated

catalog-redesign โ€” Interactive scaffold form on s

Pressing s from the catalog list or detail view now opens an in-TUI form that prompts for every variable/value the selected component exposes. The form is modal: in navigate mode j and k (or the arrow keys) move between fields and enter interacts with the focused one. Required entries are flagged, and optional entries show their default in a muted style until the user opts in.

enter on a text or HCL field switches the form into edit mode. Typing edits the value in place; esc returns to navigate. Only fields the user actually changes get written to the generated file, and optional defaults stay implicit, so the result is leaner than the placeholder flow.

enter on a boolean field toggles between [x] true and [ ] false directly, without a separate edit mode.

x on an optional field marks it "use default" again, removing any in-progress value and leaving the source's default to apply.

Complex types (lists, maps, objects) accept raw HCL and are validated before the file is written, so a typo surfaces inline rather than producing a broken terragrunt.hcl or terragrunt.values.hcl file.

ctrl+d finishes the form. Required fields the user never set still write as # TODO: fill in value so the rest of the file is usable.

S (capital) keeps the previous placeholder-only flow, generating the same TODO-laden file as before for users who prefer to populate values by editing the generated file.

stack-dependencies: parser tolerates HCL expressions throughout terragrunt.stack.hcl

The stack-dependencies experiment now defers evaluation of source, path, values, and include.path until each unit or stack block is parsed on its own. As a result, autoinclude resolution during stack generation and run --all discovery no longer fall over when other parts of a stack file use Terragrunt functions, local.*, or values.*. A few adjacent behaviors are tightened up at the same time.

Autoinclude resolves even when sibling units use expressions.

Before 1.0.6, if any unit in a stack file used a function call or a local.* / values.* reference in source, path, or values, generating an autoinclude on a different unit in the same file could fail. The parser now leaves those expressions alone until they're needed, so an unrelated unit can carry an autoinclude block without being blocked by its neighbors:

locals {
  shared_region = "us-east-1"
}

unit "account" {
  source = "${get_terragrunt_dir()}/../catalog/units/account"
  path   = "account"
  values = {
    account = values.account
    region  = local.shared_region
  }
}

unit "roles" {
  source = "${get_terragrunt_dir()}/../catalog/units/roles"
  path   = "roles"

  autoinclude {
    dependency "account" {
      config_path = unit.account.path
    }
  }
}

include blocks in terragrunt.stack.hcl accept computed paths.

The path attribute on an include block can be an HCL expression, not just a string literal. An autoinclude block in the included file is resolved normally after the include merges in:

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

What's Changed

New Contributors

Full Changelog: v1.0.5...v1.0.6

Don't miss a new terragrunt release

NewReleases is sending notifications on new releases.