Skip to content

Filters

The --filter flag provides a sophisticated querying syntax for targeting specific units and stacks in Terragrunt commands. This unified approach offers powerful filtering capabilities using a flexible query language.

The filter syntax allows you to target units and stacks using several different approaches. Usage of the filter flag in a command can look like this:

Terminal window
$ terragrunt find --filter './prod/** | name=web'
prod/services/web

Where the result of find above might have been:

Terminal window
$ terragrunt find
prod/services/web
prod/services/api
prod/data/db
dev/services/web
dev/services/api
dev/data/db

For the following file tree:

  • Directoryprod
    • Directoryservices
      • Directoryweb <— Matched by the filter
        • terragrunt.hcl
      • Directoryapi
        • terragrunt.hcl
    • Directorydata
      • Directorydb
        • terragrunt.hcl
  • Directorydev
    • Directoryservices
      • Directoryweb
        • terragrunt.hcl
      • Directoryapi
        • terragrunt.hcl
    • Directorydata
      • Directorydb
        • terragrunt.hcl

There are several different types of filter expressions, and particular ways in which they can be combined to achieve different results. You can learn more about that below.

Filter TypeDescription
NameMatch units and stacks by their name.
PathMatch units and stacks by their file system path.
AttributeMatch units and stacks by their configuration attributes.
NegatedExclude units and stacks using the ! prefix.
IntersectionUse the | operator to refine results.
UnionCombine filter results using multiple --filter flags.
GraphFilter units based on their dependency relationships using graph traversal operators.
GitFilter units and stacks based on Git diffs using Git expressions.

Match units and stacks by their name. This is the simplest form of filtering.

Terminal window
# Exact match
terragrunt find --filter app1
# Glob pattern
terragrunt find --filter 'app*'
  • Directoryapps
    • Directoryapp1 <— Matched by the first and second filter
      • terragrunt.hcl
    • Directoryapp2 <— Matched only by the second filter
      • terragrunt.hcl
    • Directoryother
      • terragrunt.hcl

Match units and stacks by their file system path.

Terminal window
# Relative paths
terragrunt find --filter './envs/prod/apps/app1'
terragrunt find --filter './envs/stage/**'
# Absolute paths
terragrunt find --filter '/absolute/path/to/envs/dev/apps/*'
# Wrapped paths (useful for explicitly indicating that this is a path expression)
terragrunt find --filter '{./envs/prod/apps/app2}'
  • Directoryenvs
    • Directoryprod
      • Directoryapps
        • Directoryapp1 <— Matched by the first filter
          • terragrunt.hcl
        • Directoryapp2 <— Matched by the fourth filter
          • terragrunt.hcl
    • Directorystage
      • Directoryapps
        • Directoryapp1 <— Matched by the second filter
          • terragrunt.hcl
        • Directoryapp2 <— Also matched by the second filter
          • terragrunt.hcl
    • Directorydev
      • Directoryapps
        • Directoryapp1 <— Matched by the third filter
          • terragrunt.hcl
        • Directoryapp2 <— Also matched by the third filter
          • terragrunt.hcl

Match units and stacks by their configuration attributes.

Terminal window
# Filter by component type
terragrunt find --filter 'type=unit'
terragrunt find --filter 'type=stack'
# Filter by external dependency status
terragrunt find --filter '{./**}... | external=false'
terragrunt find --filter '{./**}... | external=true'
# Explicitly filter by name (useful for explicitly indicating that this is a name expression)
terragrunt find --filter 'name=stack*'
  • Directory.
    • Directoryunit1 <— Selected by the first filter
      • terragrunt.hcl
    • Directorystack1 <— Selected by the second and fifth filter
      • terragrunt.stack.hcl
  • Directory..
    • Directorydependencies <— Note that this directory is sibling to the current working directory
      • Directorydependency-of-app1 <— Matched by the fourth filter, but not the third filter
        • terragrunt.hcl

The following are the attributes supported for attribute-based expressions:

AttributeDescription
nameMatch units and stacks by their directory basename.
typeMatch units and stacks by their type.
externalMatch units and stacks if they are external to the current working directory.
readingMatch units and stacks by the files they read.
sourceMatch units and stacks by their Terraform source URL or path specified in the terraform block of terragrunt.hcl files.

Match units and stacks by the files they read.

Consider the following file tree:

  • Directoryreading-shared-hcl
    • terragrunt.hcl
  • Directoryalso-reading-shared-hcl
    • terragrunt.hcl
  • Directorynot-reading-shared-hcl
    • terragrunt.hcl
  • shared.hcl

Suppose that reading-shared-hcl and also-reading-shared-hcl both read shared.hcl in their configurations, like so:

terragrunt.hcl
locals {
shared = read_terragrunt_config(find_in_parent_folders("shared.hcl"))
}

If you run the command terragrunt run --all --filter 'reading=shared.hcl' -- plan from the root folder, both reading-shared-hcl and also-reading-shared-hcl will be run; not not-reading-shared-hcl.

This is because the read_terragrunt_config HCL function has a special hook that allows Terragrunt to track that it has read the file shared.hcl. This hook is used by all native HCL functions that Terragrunt supports which read files.

Note, however, that there are certain scenarios where Terragrunt may not be able to track that a file has been read this way.

For example, you may be using a bash script to read a file via run_cmd, or reading the file via OpenTofu/Terraform code. To support these use-cases, the mark_as_read function can be used to explicitly mark a file as read in the unit.

That would look something like this:

terragrunt.hcl
locals {
filename = mark_as_read("file-read-by-tofu.txt")
}
inputs = {
filename = local.filename
}

Match units and stacks by their Terraform source URL or path specified in the terraform block of terragrunt.hcl files.

Terminal window
# Filter by exact source match
terragrunt find --filter 'source=github.com/acme/foo'
terragrunt find --filter 'source=gitlab.com/example/baz'
terragrunt find --filter 'source=./module'
# Filter by source using glob patterns
terragrunt find --filter 'source=*github.com**acme/*'
terragrunt find --filter 'source=git::git@github.com:acme/**'
terragrunt find --filter 'source=**github.com**'
terragrunt find --filter 'source=gitlab.com/**'
  • Directory.
    • Directorygithub-acme-foo <— Matched by source=github.com/acme/foo and source=github.com**acme/
      • terragrunt.hcl (source: github.com/acme/foo)
    • Directorygithub-acme-bar <— Matched by source=github.com**acme/ and source=git::git@github.com:acme/**
      • terragrunt.hcl (source: git::git@github.com:acme/bar)
    • Directorygitlab-example-baz <— Matched by source=gitlab.com/example/baz and source=gitlab.com/**
      • terragrunt.hcl (source: gitlab.com/example/baz)
    • Directorylocal-module <— Matched by source=./module
      • terragrunt.hcl (source: ./module)
      • Directorymodule
        • main.tf
    • Directoryother-unit
      • terragrunt.hcl (source: s3://bucket/module)

Negate filter expressions using the ! prefix. Negated expressions are always evaluated after all positive expressions have been evaluated.

Terminal window
# Exclude by name
terragrunt find --filter '!app1'
# Exclude by path
terragrunt find --filter '!./prod/**'
# Exclude by type
terragrunt find --filter '!type=stack'
  • Directoryenvs
    • Directoryprod
      • Directoryapps
        • Directoryapp1 <— Excluded by both the first and second filter
          • terragrunt.hcl
        • Directoryapp2 <— Matched by all filters except the second filter
          • terragrunt.hcl
      • Directorystacks
        • Directorystack1 <— Excluded by both the second and third filter
          • terragrunt.stack.hcl
    • Directorystage
      • Directoryapps
        • Directoryapp1 <— Matched by all filters except the first filter
          • terragrunt.hcl
        • Directoryapp2 <— Matched by all filters
          • terragrunt.hcl
      • Directorystacks
        • Directorystack1 <— Matched by all filters except the third filter
          • terragrunt.stack.hcl

Use the | operator to refine results from left to right. Results must match all filters in the chain to be included.

Terminal window
# Find all components in ./prod/** that are also units
terragrunt find --filter './prod/** | type=unit'
# Find all components in ./prod/** that are not units
terragrunt find --filter './prod/** | !type=unit'
# You can chain as many filters as you want to further refine the results
terragrunt find --filter './dev/** | type=unit | !name=unit1'
  • Directoryprod
    • Directoryunits
      • Directoryunit1 <— Matched by first filter
        • terragrunt.hcl
      • Directoryunit2 <— Matched by first filter
        • terragrunt.hcl
    • Directorystacks
      • Directorystack1 <— Matched by second filter
        • terragrunt.stack.hcl
      • Directorystack2 <— Matched by second filter
        • terragrunt.stack.hcl
  • Directorydev
    • Directoryunits
      • Directoryunit1
        • terragrunt.hcl
      • Directoryunit2 <— Matched by third filter
        • terragrunt.hcl
    • Directorystacks
      • Directorystack1
        • terragrunt.stack.hcl
      • Directorystack2
        • terragrunt.stack.hcl

Specify multiple --filter flags to merge results from multiple filters.

Terminal window
# Find components named 'unit1' and 'stack1'
terragrunt find --filter unit1 --filter stack1
# Find components in ./envs/prod/* and ./envs/stage/*
terragrunt find --filter './envs/prod/*' --filter './envs/stage/*'
# Find components named 'stack2' _except_ those in ./envs/prod/* and ./envs/stage/*
terragrunt find --filter stack2 --filter '!./envs/prod/**' --filter '!./envs/stage/**'
  • Directoryenvs
    • Directoryprod
      • Directoryunit1 <— Matched by the first filter and the second filter
        • terragrunt.hcl
      • Directoryunit2 <— Matched by the second filter
        • terragrunt.hcl
      • Directorystack1 <— Matched by the first filter and the second filter
        • terragrunt.stack.hcl
      • Directorystack2 <— Matched by the second filter
        • terragrunt.stack.hcl
    • Directorystage
      • Directoryunit1 <— Matched by the first filter and the second filter
        • terragrunt.hcl
      • Directoryunit2 <— Matched by the second filter
        • terragrunt.hcl
      • Directorystack1 <— Matched by the first filter and the second filter
        • terragrunt.stack.hcl
      • Directorystack2 <— Matched by the second filter
        • terragrunt.stack.hcl
    • Directorydev
      • Directoryunit1 <— Matched by the first filter
        • terragrunt.hcl
      • Directoryunit2
        • terragrunt.hcl
      • Directorystack1 <— Matched by the first filter
        • terragrunt.stack.hcl
      • Directorystack2 <— Matched by the third filter
        • terragrunt.stack.hcl

Filter units and stacks based on their dependency relationships using graph traversal operators. This allows you to find components that depend on a target, or components that a target depends on.

Graph-based expressions use the ellipsis (...) operator to indicate graph traversal direction and the caret (^) operator to exclude the target from results.

Use ... after a target expression to include the target and all of its dependencies:

Terminal window
# Find 'service' and everything it depends on
terragrunt find --filter 'service...'
  • Directory.
    • Directoryservice <— Matched (target)
      • terragrunt.hcl (depends on: db, cache, vpc)
    • Directorydb <— Matched (dependency of service)
      • terragrunt.hcl (depends on: vpc)
    • Directorycache <— Matched (dependency of service)
      • terragrunt.hcl (depends on: vpc)
    • Directoryvpc <— Matched (dependency of service, db, cache)
      • terragrunt.hcl

Use ... before a target expression to include the target and all components that depend on it:

Terminal window
# Find 'vpc' and everything that depends on it
terragrunt find --filter '...vpc'
  • Directory.
    • Directoryvpc <— Matched (target)
      • terragrunt.hcl
    • Directorydb <— Matched (depends on vpc)
      • terragrunt.hcl (depends on: vpc)
    • Directorycache <— Matched (depends on vpc)
      • terragrunt.hcl (depends on: vpc)
    • Directoryservice <— Matched (depends on vpc via db and cache)
      • terragrunt.hcl (depends on: db, cache)

Use ... before and after a target expression to include a target, all its dependencies, and all its dependents:

Terminal window
# Find 'db' and its complete dependency graph
terragrunt find --filter '...db...'
  • Directory.
    • Directoryvpc <— Matched (dependency of db)
      • terragrunt.hcl
    • Directorydb <— Matched (target)
      • terragrunt.hcl (depends on: vpc)
    • Directoryservice <— Matched (depends on db)
      • terragrunt.hcl (depends on: db, cache)

Use ^ before a target expression to exclude the target from results. This is useful when you want only the dependencies or dependents, but not the target itself:

Terminal window
# Find all dependents of 'vpc' but exclude 'vpc' itself
terragrunt find --filter '...^vpc'
  • Directory.
    • Directoryvpc <— Not matched by ’…^vpc’ (would be matched if …vpc was used)
      • terragrunt.hcl
    • Directorydb <— Matched by ’…^vpc’ (dependent on vpc)
      • terragrunt.hcl
    • Directorycache <— Matched by ’…^vpc’ (dependent on vpc)
      • terragrunt.hcl
    • Directoryservice <— Excluded by ’…^vpc’ (dependent on vpc)
      • terragrunt.hcl

Match units and stacks based on changes between Git references. This is useful for targeting infrastructure that has been modified, added, or removed between commits, branches, or tags.

Git-based expressions are written between [ and ] characters, and use the ... operator to indicate the range of changes to compare.

Terminal window
# Compare between two references
terragrunt find --filter '[main...HEAD]'
# Shorthand: compare reference to HEAD
terragrunt find --filter '[main]'
# Compare between specific commits
terragrunt find --filter '[abc123...def456]'
# Compare between tags
terragrunt find --filter '[v1.0.0...v2.0.0]'
# Compare using relative references
terragrunt find --filter '[HEAD~1...HEAD]'
# Compare between branches
terragrunt find --filter '[feature-branch...main]'
  • Directory.
    • Directorymodified-unit <— Matched by [main…HEAD] (terragrunt.hcl was modified)
      • terragrunt.hcl (modified)
    • Directorynew-unit <— Matched by [main…HEAD] (terragrunt.hcl was added)
      • terragrunt.hcl (added)
    • Directoryremoved-unit <— Matched by [main…HEAD] (terragrunt.hcl was removed)
      • (directory removed)
    • Directoryunchanged-unit
      • terragrunt.hcl (unchanged)

If you want to ensure that certain units are always included or excluded, you can use a filters file.

Filters files are simple text files that contain filter expressions delimited by newlines. Empty lines and lines starting with # are ignored.

filters.txt
./subtree/**
!./subtree/dependency/**
Terminal window
terragrunt run --all --filters-file filters.txt -- plan

Running Terragrunt like this is equivalent to running it with the following flags:

Terminal window
terragrunt run --all --filter './subtree/**' --filter '!./subtree/dependency/**' -- plan

The following commands all support the --filter flag using the same filtering syntax (note the section below on special interactions):

This flag is intended to be a flexible way to target specific infrastructure that allows you to dry-run infrastructure targeting using discovery commands (like find and list) before running a command that actually affects infrastructure (like run).

The --filter flag provides a unified alternative to multiple queue control flags.

Legacy FlagFilter Equivalent
--queue-include-dir=./path--filter='./path'
--queue-exclude-dir=./path--filter='!./path'
--queue-include-external--filter='{./**}...'
--queue-include-units-reading=shared.hcl--filter='reading=shared.hcl'

Certain commands have special interactions with the --filter flag that are worth noting.

Unlike when used for most commands, the --filter flag is used to filter on individual HCL files when used with the hcl fmt.

All other commands use --filter to filter on units and/or stacks (which are directories). As a result, only path-based filter expressions are supported. Attribute-based filters like type=unit or name=my-app are not applicable to file-level operations.

Example:

Terminal window
# Supported: Path-based expressions
terragrunt hcl fmt --filter './prod/**/*.hcl'
# Not supported: Attribute-based expressions
terragrunt hcl fmt --filter 'type=unit' # This will not work

When using --filter with stack generate, filter expressions will only be recognized if they explicitly target stacks. This is to ensure that filters are not over-applied, preventing any stack generation from occurring.

Terminal window
# Supported: Only generate the stacks that match the filter, as we are explicitly indicating that we are targeting stacks.
terragrunt stack generate --filter 'name=prod | type=stack'
# Not supported: This filter will be ignored, as we are not explicitly indicating that we are targeting stacks.
terragrunt stack generate --filter 'name=prod' # This will not work

The reason for this is that stack generation can also be done automatically as part of other commands, like run, and thus we need to make it clear that we’re trying to control stack generation rather than run behavior.

Terminal window
# This will run any unit named 'vpc'
terragrunt run --all --filter 'vpc' -- plan
# This will run any unit named 'vpc', and prevent stack generation in any stack not named 'dev' (including any stacks named 'vpc')
terragrunt stack run --filter 'vpc' --filter 'name=dev | type=stack' -- apply