> For the complete documentation index, see [llms.txt](https://docs.firefly.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.firefly.ai/detailed-guides/workflows/filtered-terragrunt-runs.md).

# Filtered Terragrunt Runs (Run Only Changed Units)

> **Related Guides:**
>
> * [Creating New Firefly Workflows](/detailed-guides/workflows/creating-workflows.md): How to create a workspace and choose its Terragrunt version.
> * [Path Configurations (Change-Based Triggers)](/detailed-guides/workflows/path-configurations.md): Deciding *whether* a workspace runs at all.
> * [Triggering Workspace Deployment](/detailed-guides/workflows/trigger-deploy.md): Manually triggering a deployment from the UI.

A Terragrunt workspace with **Run All** enabled runs every unit under its working directory on every trigger. In a repository with dozens of units, a one-line change to a single database configuration still plans everything — slow, noisy, and expensive.

**Filtered runs** narrow each run to the units your commits actually touched, plus any unit that depends on them. A change to one unit plans one unit. Everything else is skipped.

This is especially useful for:

* **Large unit trees**, where a full `run --all` takes many minutes but a typical change touches one or two units.
* **Shared repositories**, where several teams commit to the same Terragrunt root and each wants feedback only on their own units.
* **Pull request reviews**, where a plan covering thirty untouched units buries the one plan a reviewer needs to read.

## Prerequisites

| Requirement                           | Why                                                                                                                             |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| A **GitHub** or **GitLab** repository | Firefly works out the commit range from the provider. Bitbucket and Azure DevOps cannot supply one.                             |
| A **Terragrunt** workspace            | The feature filters Terragrunt units. It does not apply to plain Terraform or OpenTofu workspaces.                              |
| **Run All** enabled                   | Filtering narrows a `run --all` run. With Run All off, the workspace already runs a single unit and there is nothing to filter. |
| Terragrunt **1.1.1 or newer**         | Earlier versions cannot expand a filter across the dependency graph. Firefly will not filter a run below this version.          |

Filtered runs are being rolled out per account. If the **Filter Changed Units** section does not appear in your workspace settings, contact your Firefly account team to have it enabled.

## Supported VCS Providers

Filtered runs are available on **GitHub** and **GitLab**.

| Provider     | Filtered runs |
| ------------ | ------------- |
| GitHub       | Supported     |
| GitLab       | Supported     |
| Bitbucket    | Not supported |
| Azure DevOps | Not supported |

On Bitbucket and Azure DevOps, Firefly cannot work out the range of commits a run covers, so it has nothing to hand Terragrunt and cannot filter. Leave **Run only changed units** off on workspaces backed by those providers: a pull request run that asks for a filtered plan will fail rather than quietly planning everything.

## Enabling Filtered Runs

You can enable filtering when you create a workspace, or on an existing one.

1. Open the workspace and go to its **General Configuration** settings.
2. Set the **IaC type** to Terragrunt and choose a Terragrunt version of **1.1.1 or newer**.
3. Enable **Run All**.
4. Under **Filter Changed Units**, turn on **Run only changed units**.
5. Save the workspace.

The setting is also available in the **Bulk Onboarding** wizard, so you can enable it across many workspaces as you onboard them.

Turning **Run All** off clears **Run only changed units** — the two settings are saved together, and filtering has no meaning without Run All.

No change to your repository is required. You do not need to add configuration files, annotate your units, or declare which files belong to which unit.

## We Use Terragrunt's Own Filtering

Firefly does not calculate the list of units to run, and does not parse your Terragrunt configuration to work out what changed.

Instead, Firefly works out the range of commits your run covers and hands that range to Terragrunt using Terragrunt's own built-in change filter:

```
terragrunt run --all plan --filter '...[<start-commit>...<end-commit>]'
```

Terragrunt reads its own dependency graph and decides which units fall inside that range. The leading `...` is what tells Terragrunt to also include units that *depend on* a changed unit.

This matters for two reasons:

* **The unit selection follows Terragrunt's rules, not ours.** If Terragrunt considers a unit affected, it runs. Behavior matches what you would get running the equivalent Terragrunt command yourself.
* **The behavior can change with your Terragrunt version.** Because the selection is Terragrunt's, upgrading the Terragrunt version on your workspace may change which units are selected. The examples below were verified against **Terragrunt 1.1.1**.

## How Change Discovery Works

Terragrunt compares the two ends of the commit range, works out which files changed between them, maps those files to the units that own them, and then walks the dependency graph to add every unit that depends on a selected one.

### Example

Consider a workspace whose working directory contains three units, where `api` consumes an output from `network`:

```
live/
├── network/     terragrunt.hcl
├── database/    terragrunt.hcl
└── api/         terragrunt.hcl   →  dependency { config_path = "../network" }
```

With **Run only changed units** enabled:

| Your pull request changes | Units that run                     | Why                                                                                   |
| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------- |
| `database/terragrunt.hcl` | `database` — **1 unit**            | Nothing depends on `database`, so the change stops there.                             |
| `network/terragrunt.hcl`  | `network` and `api` — **2 units**  | `api` declares a dependency on `network`, so it is pulled in automatically.           |
| `README.md`               | **none**                           | No unit owns the file. The run completes with nothing to plan.                        |
| `database/` and `api/`    | `database` and `api` — **2 units** | Both are touched directly. `network` is untouched and nothing depends on it changing. |

Without filtering, every one of these pull requests would run all three units.

### Which Commits Are Compared

The range Firefly sends depends on how the run was triggered:

| Trigger                                                                      | Compared range                                                                                     |
| ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Pull request opened or updated                                               | The point where your branch diverged from the target branch, up to the latest commit on the branch |
| Apply of an approved pull request run                                        | The same range that was planned                                                                    |
| Merge of a pull request, or any other push to the workspace's default branch | The commit the branch pointed at **before** the push, up to the pushed commit                      |
| Manual deployment of a **non-default** branch                                | The point where the branch diverged from the default branch, up to the commit being deployed       |
| Manual deployment of the **default** branch                                  | **Not filtered** — every unit runs                                                                 |

A push and a manual deployment are different triggers even on the same branch. A push carries its own *before* and *after* commits, so it can be filtered; a manual deployment names one commit with nothing to compare it against. A push to any other branch does not start a run at all — a workspace only reacts to pushes on its own default branch.

Filtering applies to both the **plan** and the **apply**. When you approve a filtered plan, the apply covers the same units, so what you reviewed is what gets applied.

## How Filtering Interacts with the Working Directory

Enabling filtering does not change what your working directory is for. Two separate decisions are made, in order, and filtering only affects the second:

1. **Does this workspace run at all?** Unchanged. A workspace runs when a changed file falls under its working directory, or matches one of its [path configurations](/detailed-guides/workflows/path-configurations.md). This is how Firefly decides the workspace is affected, with or without filtering.
2. **Which units inside it run?** This is what filtering adds. Your working directory is the root Terragrunt runs from, and the filter narrows the units beneath it.

Filtering only ever narrows. It cannot widen a run beyond the working directory, and a change outside the working directory never selects a unit inside it.

### A Run Can Be Triggered and Then Select Nothing

The two decisions are made against different things — the first against file paths, the second against Terragrunt's unit graph — so a change can satisfy the first and not the second.

The clearest example is a file that lives under your working directory but belongs to no unit, such as a `README.md`:

* The file is under the working directory, so the workspace is marked as changed and a run starts.
* No unit owns the file, so the filter selects **no units** and the run finishes without planning anything.

The same change on a workspace without filtering would have planned every unit.

> **This is easy to mistake for a workspace that did not run.** A run that selects no units posts no plan comment on the pull request, so the pull request looks the same as if the workspace had been skipped entirely. The run itself exists — open the workspace in Firefly, where it is recorded as completed with no changes to plan.

## Limitations

**Branch creation is not filtered.** The first push that creates a branch has no earlier commit to compare against, so that run covers every unit.

**Manual deployments of the default branch are not filtered.** There is no other branch to compare the default branch against, so these runs cover every unit.

**Destroy runs are never filtered.** A destroy tears down the whole workspace, so every unit runs regardless of this setting.

**Only files that Terragrunt attributes to a unit are detected.** Terragrunt maps changed files to units through its own configuration graph. A file that a unit reads at runtime but that Terragrunt does not treat as part of that unit — for example a data file loaded by your module — will not cause that unit to be selected. Changes to a module's `.tf` code *are* detected. If you depend on external files that Terragrunt cannot see, keep a full run for that workspace.

**Runs fall back to a full run when the range cannot be determined.** If Firefly cannot work out the comparison range — for example the branch history is unavailable — the run executes every unit rather than silently running too few.

**Filtering narrows units within a workspace, not which workspaces run.** Deciding whether a workspace is triggered at all is a separate mechanism — see [Path Configurations](/detailed-guides/workflows/path-configurations.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.firefly.ai/detailed-guides/workflows/filtered-terragrunt-runs.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
