Combining Expressions
Negated Expressions
Section titled “Negated Expressions”Negate filter expressions using the ! prefix. Negated expressions are always evaluated after all positive expressions have been evaluated.
# Exclude by nameterragrunt find --filter '!app1'
# Exclude by pathterragrunt find --filter '!./prod/**'
# Exclude by typeterragrunt 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
Intersection Expressions
Section titled “Intersection Expressions”Use the | operator to refine results from left to right. Results must match all filters in the chain to be included.
# Find all components in ./prod/** that are also unitsterragrunt find --filter './prod/** | type=unit'
# Find all components in ./prod/** that are not unitsterragrunt find --filter './prod/** | !type=unit'
# You can chain as many filters as you want to further refine the resultsterragrunt 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
Path resolution in intersection chains
Section titled “Path resolution in intersection chains”In an intersection chain (A | B | C), the left-most expression determines which components flow through the rest of the chain. Each component carries its own discovery context, including a working directory where the component was discovered.
Relative path expressions (like ./apps/*) in any part of the chain resolve against the working directory of the component’s discovery context — not the user’s current working directory. These two are the same when discovering components in the current working directory.
# Referencing the file tree aboveterragrunt run --working-dir prod --filter './units/** | unit1'When using Git expressions, components are discovered in temporary Git worktrees (see How it works for more details. As such, relative paths resolve relative to the root of the Git worktree where the component was discovered.
# Note that we still need to specify 'prod' here in the path.terragrunt run --working-dir prod --filter '[main...HEAD] | ./prod/units/**'Union Expressions
Section titled “Union Expressions”Specify multiple --filter flags to merge results from multiple filters.
# 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
Unions of negated filters
Section titled “Unions of negated filters”When a filter query starts with a negation (!), the result is applied after all positive filters have been applied.
This means that if you have a filter query like this:
terragrunt find --filter '!type=unit' --filter 'name=unit1'The result will be the components that are not units and are named unit1.
This means that you should be able to expect negative filters to take effect regardless of how other positive filters may result in the addition of results.
Unions with Git expressions
Section titled “Unions with Git expressions”Union deduplication in filter results is based on the absolute path of each discovered component. When combining Git expressions with non-Git expressions in a union, it might seem like the same unit has appeared twice. e.g.
$ terragrunt find --filter '[main...HEAD]' --filter ./live/foolive/foolive/fooThe reason for this is usually that a unit with the same name has been discovered twice: once discovered from your current working directory and once from a git worktree. From Terragrunt’s perspective, these are two different units and can be operated on independently.
If your intent is not to use Terragrunt in this way (to operate on units in temporary Git worktrees and units in your current working directory independently), you can use the find command instead to perform the logic of discovering components that have changed between Git references, then separately perform a run against units in your current working directory.
terragrunt find --filter '[main...HEAD]' | awk '{printf "{%s}\n", $0}' > /tmp/diffs.txtterragrunt run --all --filters-file /tmp/diffs.txt -- plan