---
title: Filters
description: Learn how to use the --filter flag to target specific infrastructure
slug: docs/features/filter
sidebar:
  order: 18
---

import { Aside } from '@astrojs/starlight/components';
import FileTree from '@components/vendored/starlight/FileTree.astro';

The `--filter` flag provides a sophisticated querying syntax for targeting specific [units](/docs/features/units) and [stacks](/docs/features/stacks) in Terragrunt commands. This unified approach offers powerful filtering capabilities using a flexible query language.

## Filter Syntax Overview

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:

```bash
$ terragrunt find --filter './prod/** | name=web'
prod/services/web
```

Where the result of `find` above might have been:

```bash
$ 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:

<FileTree>
- prod
  - services
    - **web** \<-- Matched by the filter
      - terragrunt.hcl
    - api
      - terragrunt.hcl
  - data
    - db
      - terragrunt.hcl
- dev
  - services
    - web
      - terragrunt.hcl
    - api
      - terragrunt.hcl
  - data
    - db
      - terragrunt.hcl
</FileTree>

## Filter Expressions

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 Type | Description |
|-------------|-------------|
| Name | Match units and stacks by their name. |
| Path | Match units and stacks by their file system path. |
| Attribute | Match units and stacks by their configuration attributes. |
| Negated | Exclude units and stacks using the `!` prefix. |
| Intersection | Use the `\|` operator to refine results. |
| Union | Combine filter results using multiple `--filter` flags. |
| Graph | Filter units based on their dependency relationships using graph traversal operators. |
| Git | Filter units and stacks based on Git diffs using Git expressions. |

### Name-Based Expressions

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

```bash
# Exact match
terragrunt find --filter app1

# Glob pattern
terragrunt find --filter 'app*'
```

<FileTree>
- apps
  - **app1** \<-- Matched by the first and second filter
    - terragrunt.hcl
  - **app2** \<-- Matched only by the second filter
    - terragrunt.hcl
  - other
    - terragrunt.hcl
</FileTree>

<Aside type="note">
Note that `app1` and `app2` were selected _within_ the `apps` directory. Filtering on names will match _any_ unit/stack that has a directory basename name matching a filter.
</Aside>

### Path-Based Expressions

Match units and stacks by their file system path.

```bash
# 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}'
```

<FileTree>
- envs
  - prod
    - apps
      - **app1** \<-- Matched by the first filter
        - terragrunt.hcl
      - **app2** \<-- Matched by the fourth filter
        - terragrunt.hcl
  - stage
    - apps
      - **app1** \<-- Matched by the second filter
        - terragrunt.hcl
      - **app2** \<-- Also matched by the second filter
        - terragrunt.hcl
  - dev
    - apps
      - **app1** \<-- Matched by the third filter
        - terragrunt.hcl
      - **app2** \<-- Also matched by the third filter
        - terragrunt.hcl
</FileTree>

<Aside type="note">
Note that globs used in path-based expressions will not recursively match nested directories unless you use the `**` wildcard.

(That's why `./envs/stage/**` is used above)
</Aside>

<Aside type="note">

Glob patterns must use Unix forward slashes `/` to separate directories, even on Windows machines.

</Aside>

### Attribute-Based Expressions

Match units and stacks by their configuration attributes.

```bash
# 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*'
```

<FileTree>
- .
  - **unit1** \<-- Selected by the first filter
    - terragrunt.hcl
  - **stack1** \<-- Selected by the second and fifth filter
    - terragrunt.stack.hcl
- ..
  - dependencies \<-- Note that this directory is sibling to the current working directory
    - **dependency-of-app1** \<-- Matched by the fourth filter, but not the third filter
        - terragrunt.hcl
</FileTree>

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

| Attribute | Description |
|-----------|-------------|
| name | Match units and stacks by their directory basename. |
| type | Match units and stacks by their type. |
| external | Match units and stacks if they are external to the current working directory. |
| reading | Match units and stacks by the files they read. |
| source | Match units and stacks by their Terraform source URL or path specified in the `terraform` block of `terragrunt.hcl` files. |

### Reading-Based Expressions

Match units and stacks by the files they read.

Consider the following file tree:

<FileTree>

- reading-shared-hcl
  - terragrunt.hcl
- also-reading-shared-hcl
  - terragrunt.hcl
- not-reading-shared-hcl
  - terragrunt.hcl
- shared.hcl

</FileTree>

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

```hcl
# 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`](/docs/reference/hcl/functions/#run_cmd), or reading the file via OpenTofu/Terraform code. To support these
use-cases, the [`mark_as_read`](/docs/reference/hcl/functions/#mark_as_read) function can be used to explicitly mark a file as read in the unit.

That would look something like this:

```hcl
# terragrunt.hcl

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

inputs = {
  filename = local.filename
}
```
<Aside type="caution">
Due to how Terragrunt parses configurations during `run --all`, functions will only properly mark files as read if they are used outside the `inputs` attribute.

Reading a file directly in the `inputs` attribute will not mark the file as read, as the `inputs` attribute is not parsed until after the queue has already been populated to support rendering of dependency outputs, which are only available after dependencies have been run.
</Aside>

### Source-Based Expressions

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

```bash
# 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/**'
```

<FileTree>
- .
  - **github-acme-foo** \<-- Matched by source=github.com/acme/foo and source=*github.com**acme/*
    - terragrunt.hcl (source: github.com/acme/foo)
  - **github-acme-bar** \<-- Matched by source=*github.com**acme/* and source=git::git@github.com:acme/**
    - terragrunt.hcl (source: git::git@github.com:acme/bar)
  - **gitlab-example-baz** \<-- Matched by source=gitlab.com/example/baz and source=gitlab.com/**
    - terragrunt.hcl (source: gitlab.com/example/baz)
  - **local-module** \<-- Matched by source=./module
    - terragrunt.hcl (source: ./module)
    - module
      - main.tf
  - other-unit
    - terragrunt.hcl (source: s3://bucket/module)
</FileTree>

<Aside type="note">
The `source=` filter matches against the Terraform source URL or path specified in the `terraform` block of `terragrunt.hcl` files in units. It supports glob patterns, allowing you to match multiple sources with patterns like `*github.com**` or `gitlab.com/**`. This is useful for filtering units that use specific module sources, such as all units using a particular GitHub organization's modules or all local modules.

This attribute may be supported on stacks in the future.
</Aside>

### Negated Expressions

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

```bash
# Exclude by name
terragrunt find --filter '!app1'

# Exclude by path
terragrunt find --filter '!./prod/**'

# Exclude by type
terragrunt find --filter '!type=stack'
```

<FileTree>
- envs
  - prod
    - apps
      - app1 \<-- Excluded by _both_ the first and second filter
        - terragrunt.hcl
      - app2 \<-- Matched by all filters _except_ the second filter
        - terragrunt.hcl
    - stacks
      - **stack1** \<-- Excluded by _both_ the second and third filter
        - terragrunt.stack.hcl
  - stage
    - apps
      - **app1** \<-- Matched by all filters _except_ the first filter
        - terragrunt.hcl
      - **app2** \<-- Matched by all filters
        - terragrunt.hcl
    - stacks
      - **stack1** \<-- Matched by all filters _except_ the third filter
        - terragrunt.stack.hcl

</FileTree>

### Intersection Expressions

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

```bash
# 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'
```

<FileTree>
- prod
  - units
    - **unit1** \<-- Matched by first filter
      - terragrunt.hcl
    - **unit2** \<-- Matched by first filter
      - terragrunt.hcl
  - stacks
    - **stack1** \<-- Matched by second filter
      - terragrunt.stack.hcl
    - **stack2** \<-- Matched by second filter
      - terragrunt.stack.hcl
- dev
  - units
    - unit1
      - terragrunt.hcl
    - **unit2** \<-- Matched by third filter
      - terragrunt.hcl
  - stacks
    - stack1
      - terragrunt.stack.hcl
    - stack2
      - terragrunt.stack.hcl
</FileTree>

### Union Expressions

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

```bash
# 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/**'
```

<FileTree>
- envs
  - prod
    - **unit1** \<-- Matched by the first filter _and_ the second filter
      - terragrunt.hcl
    - **unit2** \<-- Matched by the second filter
      - terragrunt.hcl
    - **stack1** \<-- Matched by the first filter _and_ the second filter
      - terragrunt.stack.hcl
    - **stack2** \<-- Matched by the second filter
      - terragrunt.stack.hcl
  - stage
    - **unit1** \<-- Matched by the first filter _and_ the second filter
      - terragrunt.hcl
    - **unit2** \<-- Matched by the second filter
      - terragrunt.hcl
    - **stack1** \<-- Matched by the first filter _and_ the second filter
      - terragrunt.stack.hcl
    - **stack2** \<-- Matched by the second filter
      - terragrunt.stack.hcl
  - dev
    - **unit1** \<-- Matched by the first filter
      - terragrunt.hcl
    - unit2
      - terragrunt.hcl
    - **stack1** \<-- Matched by the first filter
      - terragrunt.stack.hcl
    - **stack2** \<-- Matched by the third filter
      - terragrunt.stack.hcl
</FileTree>

<Aside type="caution" title="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:

```bash
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.

</Aside>

<Aside type="tip" title="Using Negated Expressions">
If you have infrastructure that you _never_ want to run, you can consider leveraging the [`--filters-file`](#filters-file) to automatically negate them.
</Aside>

### Graph-Based Expressions

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.

#### Include Dependencies

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

```bash
# Find 'service' and everything it depends on
terragrunt find --filter 'service...'
```

<FileTree>
- .
  - **service** \<-- Matched (target)
    - terragrunt.hcl (depends on: db, cache, vpc)
  - **db** \<-- Matched (dependency of service)
    - terragrunt.hcl (depends on: vpc)
  - **cache** \<-- Matched (dependency of service)
    - terragrunt.hcl (depends on: vpc)
  - **vpc** \<-- Matched (dependency of service, db, cache)
    - terragrunt.hcl
</FileTree>

#### Include Dependents

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

```bash
# Find 'vpc' and everything that depends on it
terragrunt find --filter '...vpc'
```

<FileTree>
- .
  - **vpc** \<-- Matched (target)
    - terragrunt.hcl
  - **db** \<-- Matched (depends on vpc)
    - terragrunt.hcl (depends on: vpc)
  - **cache** \<-- Matched (depends on vpc)
    - terragrunt.hcl (depends on: vpc)
  - **service** \<-- Matched (depends on vpc via db and cache)
    - terragrunt.hcl (depends on: db, cache)
</FileTree>

#### Include Both Directions

Use `...` _before and after_ a target expression to include a target, all its dependencies, and all its dependents:

```bash
# Find 'db' and its complete dependency graph
terragrunt find --filter '...db...'
```

<FileTree>
- .
  - **vpc** \<-- Matched (dependency of db)
    - terragrunt.hcl
  - **db** \<-- Matched (target)
    - terragrunt.hcl (depends on: vpc)
  - **service** \<-- Matched (depends on db)
    - terragrunt.hcl (depends on: db, cache)
</FileTree>

#### Exclude Target

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:

```bash
# Find all dependents of 'vpc' but exclude 'vpc' itself
terragrunt find --filter '...^vpc'
```

<FileTree>
- .
  - vpc \<-- Not matched by '...^vpc' (would be matched if ...vpc was used)
    - terragrunt.hcl
  - db \<-- Matched by '...^vpc' (dependent on vpc)
    - terragrunt.hcl
  - cache \<-- Matched by '...^vpc' (dependent on vpc)
    - terragrunt.hcl
  - service \<-- Excluded by '...^vpc' (dependent on vpc)
    - terragrunt.hcl
</FileTree>

<Aside type="tip">
Graph expressions require dependency/dependent information to work correctly.

When using graph expressions, Terragrunt automatically discovers dependency relationships between components to enable graph traversal. This may add some overhead compared to simple name or path filters, as Terragrunt will need to recursively parse and evaluate HCL files to determine whether there are more dependencies or dependents to include.

Note that this overhead is especially noticeable in _dependent_ graph expressions, as Terragrunt will need to recursively parse _all_ units that could _possibly_ depend on the target. Use this expression judiciously.
</Aside>

### Git-Based Expressions

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.

```bash
# 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]'
```

<FileTree>
- .
  - **modified-unit** \<-- Matched by [main...HEAD] (terragrunt.hcl was modified)
    - terragrunt.hcl (modified)
  - **new-unit** \<-- Matched by [main...HEAD] (terragrunt.hcl was added)
    - terragrunt.hcl (added)
  - **removed-unit** \<-- Matched by [main...HEAD] (terragrunt.hcl was removed)
    - (directory removed)
  - unchanged-unit
    - terragrunt.hcl (unchanged)
</FileTree>

<Aside type="caution" title="Remote State Recommended">

When using Git-based filter expressions (e.g. `[HEAD~1...HEAD]`), it is **strongly recommended** to use remote state configurations. Units discovered using Git-based filter expressions may not properly detect dependency outputs when using local state, which can lead to unexpected outcomes such as mock outputs being used instead of actual dependency outputs.

</Aside>

<Aside type="note" title="Interaction with the run command">
When using Git-based expressions and the `run` command, you are required to use one of the `plan` or `apply` commands, and not the `-destroy` flag.

This is because whether or not a unit will be destroyed is determined by logic relevant to inspecting changes in Git.

When units are added or modified between two Git references, they will be planned or applied. When the units are removed between two Git references, they will be planned for destruction (with `plan -destroy`) or destroyed (with `apply -destroy`).

In the scenario above, running the following:

```bash
terragrunt run --filter '[main...HEAD]' plan
```

Will result in the following:

- `modified-unit` will be planned (`tofu plan`)
- `new-unit` will be planned (`tofu plan`)
- `removed-unit` will be planned for destruction (`tofu plan -destroy`)
- `unchanged-unit` will be ignored

</Aside>

<Aside type="tip" title="Allowing destroys">

When using Git-based filter expressions and the run command, Terragrunt won't destroy units that are removed between the two Git references unless you use the `--filter-allow-destroy` flag.

```bash
terragrunt run --filter '[main...HEAD]' --filter-allow-destroy destroy
```

This is a safeguard to prevent unintended destruction of infrastructure.

</Aside>

<Aside type="tip" title="How it works">

When evaluating a Git-based filter, Terragrunt will first generate a worktree for every reference that needs to be evaluated, and assess the diffs between Git references.

e.g. For a filter like `[main...HEAD]`, Terragrunt will generate a worktree for `main` and one for `HEAD` in temporary directories, and use `git diff` to assess the diffs between the two references.

Then, for any unit that is discovered within those worktrees, Terragrunt will enqueue that unit for a run in the run queue _in the worktree where it was discovered_.

In the example above, the `modified-unit` will be discovered in a "to" temporary directory (e.g. `/tmp/.../terragrunt-worktree-HEAD.../modified-unit`), whereas the `removed-unit` would be discovered in the "from" temporary directory (e.g. `/tmp/.../terragrunt-worktree-main.../removed-unit`).

This is important to recognize, as it's how destroys will be possible despite the fact that the unit is no longer present in the current working directory. As a consequence, however, you may find that paths don't behave how you expect, as you will be performing runs in the temporary directories created for the relevant worktrees.

</Aside>

<Aside type="tip" title="Testing with Local State">

If you need to test with local state while using Git-based filter expressions, you can work around the limitations by placing state files in a separate location using absolute paths in your `remote_state` configuration. This ensures that state files are stored consistently regardless of which worktree directory Terragrunt is operating in.

For example, instead of using a relative path:

```hcl
remote_state {
  backend = "local"
  config = {
    path = "${get_parent_terragrunt_dir()}/.state/${path_relative_to_include()}/tofu.tfstate"
  }
}
```

Consider using an absolute path to a shared location:

```hcl
remote_state {
  backend = "local"
  config = {
    path = "/tmp/terragrunt-state/${path_relative_to_include()}/tofu.tfstate"
  }
}
```

Note that this is a workaround for testing purposes only. For production use, remote state backends (such as S3, GCS, or Azure Storage) are strongly recommended.

</Aside>

<Aside type="tip" title="--filter-affected">

For the common use case of comparing the default branch (typically `main`) with `HEAD`, you can use the `--filter-affected` flag as a convenient shorthand:

```bash
# Find components affected by changes between main and HEAD
terragrunt find --filter-affected

# Equivalent to:
terragrunt find --filter '[main...HEAD]'
```

The `--filter-affected` flag automatically detects your repository's default branch and compares it with `HEAD`.

</Aside>

#### Filters File

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.

```text
# filters.txt

./subtree/**
!./subtree/dependency/**
```

```bash
terragrunt run --all --filters-file filters.txt -- plan
```

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

```bash
terragrunt run --all --filter './subtree/**' --filter '!./subtree/dependency/**' -- plan
```

<Aside type="tip">

If you want to automatically configure certain filters to be applied by default, you can name the filters file `.terragrunt-filters`.

Terragrunt will automatically read filters from this file if it exists in the current working directory.

</Aside>

## Usage with Commands

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

- [find](/docs/reference/cli/commands/find)
- [list](/docs/reference/cli/commands/list)
- [run](/docs/reference/cli/commands/run)
- [hcl fmt](/docs/reference/cli/commands/hcl/fmt)
- [hcl validate](/docs/reference/cli/commands/hcl/validate)
- [stack run](/docs/reference/cli/commands/stack/run)
- [stack generate](/docs/reference/cli/commands/stack/generate)

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`).

## Comparison with Queue Control Flags

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

| Legacy Flag | Filter 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'` |

<Aside type="tip" title="Queue flag aliases">

If you are currently using those queue control flags, note that you are actually already using the equivalent filter expressions, as they are aliased internally.

You will generally have a better experience using the filter flag instead, as it provides a more powerful and flexible way to target infrastructure.

</Aside>

## Special Interactions

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

### `hcl fmt`

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:

```bash
# 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
```

### `stack generate`

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.

```bash
# 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.

```bash
# 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
```
