# atmos terraform plan

Use this command to generate a Terraform execution plan for an Atmos component in a stack, showing what changes would be made to your infrastructure.

## Usage

Execute the `terraform plan` command like this:

```shell
atmos terraform plan <component> -s <stack> [options]
```

This command generates an execution plan that shows:

- Resources that will be created, modified, or destroyed
- Changes to resource attributes
- Data source reads that will be performed

By default, Atmos saves the plan to a file using a standardized naming convention: `<context>-<component>.planfile`. This planfile can later be used with `atmos terraform apply --from-plan` to ensure that only the reviewed changes are applied.

:::tip
Run `atmos terraform plan --help=all` to see shared selector and dependency flags.
:::

## Examples

### Basic Planning

Generate a plan for the `vpc` component in the `dev` stack:

```shell
atmos terraform plan vpc -s dev
```

### Custom Planfile Output

Save the plan to a specific file using the `-out` flag (native Terraform flag):

```shell
atmos terraform plan vpc -s dev -out=my-custom.planfile
```

### Skip Planfile Generation

When using Terraform Cloud (which doesn't support the `-out` flag), skip planfile generation:

```shell
atmos terraform plan vpc -s dev --skip-planfile
```

### Planning with Variable Overrides

Pass additional variables to the plan:

```shell
atmos terraform plan vpc -s dev -var="instance_type=t3.large"
```

### Targeted Planning

Plan changes only for specific resources:

```shell
atmos terraform plan vpc -s dev -target=aws_subnet.private
```

### Destroy Planning

Generate a plan to destroy infrastructure:

```shell
atmos terraform plan vpc -s dev -destroy
```

### Graph-backed Multi-component Planning

Run plans for multiple components through the Terraform dependency graph:

```shell
# Plan every Terraform component in dependency order
atmos terraform plan --all -s dev

# Plan a named subset, preserving dependency edges between selected components
atmos terraform plan --components vpc,eks/cluster,eks/apps -s dev

# Plan components selected by query
atmos terraform plan --query '.settings.tier == "network"' -s dev
```

The graph is built from [`dependencies.components`](/stacks/dependencies/components) first, with `settings.depends_on` as a fallback. Components that are independent at the same point in the graph can run concurrently when `--max-concurrency` is greater than `1`.

```shell
atmos terraform plan --all -s dev --max-concurrency 4
```

Concurrent plan output is isolated per component. Use `--log-order grouped` to print each component's logs together after it finishes, or keep the default `stream` mode to see logs as they arrive. To reduce noise from unchanged components, use `--hide=no-changes`.

```shell
atmos terraform plan --all -s dev \
  --max-concurrency 4 \
  --failure-mode keep-going \
  --log-order grouped \
  --hide=no-changes \
  --execution-summary-file /tmp/atmos-plan-summary.json
```

### GitHub Actions CI Output

When CI mode is enabled with `--ci`, `ci.enabled: true`, or GitHub Actions auto-detection,
graph-backed multi-component `plan` runs write a single aggregate CI result after the scheduler
finishes. This applies to `--all`, `--components`, and `--query` plan runs. Single-component
`plan`, `apply`, and `deploy` keep their existing per-command CI output.

In GitHub Actions, the aggregate result writes once to `$GITHUB_STEP_SUMMARY` and `$GITHUB_OUTPUT`.
The job summary includes component counts, total resource counts, failed/changed/no-change/skipped
groups, a per-component table, and details for failed or changed components. Output variables include
`has_changes`, `has_errors`, `exit_code`, resource totals, component totals, `summary`, `command`,
`stack`, and `component`.

Aggregate exit codes follow Terraform plan semantics across the whole graph:

| Exit Code | Meaning |
| ---: | --- |
| `1` | At least one component failed |
| `2` | No failures, but at least one component has changes |
| `0` | No failures and no changes |

## Planfile Management

### Default Behavior

When you run `atmos terraform plan`, Atmos automatically:

1. Generates a planfile with the naming pattern:
   - Without folder prefix: `<context>-<component>.planfile`
   - With folder prefix: `<context>-<folder_prefix>-<component>.planfile`

2. Saves the planfile in the component's working directory

3. The planfile can be used later with:
   ```shell
   atmos terraform apply <component> -s <stack> --from-plan
   ```

### Custom Planfile Locations

You can specify a custom planfile location using the standard Terraform `-out` flag:

```shell
# Absolute path
atmos terraform plan vpc -s dev -out=/tmp/my-plan.tfplan

# Relative path (relative to component directory)
atmos terraform plan vpc -s dev -out=plans/vpc.tfplan
```

### Skipping Planfile Generation

To run a plan without generating a planfile (useful for quick checks or when using Terraform Cloud):

```shell
atmos terraform plan vpc -s dev --skip-planfile
```

You can also configure this globally in `atmos.yaml`:

```yaml
components:
  terraform:
    plan:
      skip_planfile: true
```

## Arguments

- **`component` (required)**

  Atmos component name to plan.

## Flags

- **`--use-mocks` (optional)**

  Use the producer's literal [component mocks](/stacks/components/mocks) for
  `!terraform.state` and `!terraform.output` lookups. Accepts these values:
  - Absent, empty, or a false boolean (`false`, `0`, `f`): mocks are off.
  - Bare `--use-mocks`, a true boolean (`true`, `1`, `t`), or `ATMOS_USE_MOCKS=true`: mocks are on, using
    [`components.terraform.mocks.mode`](/cli/configuration/components/terraform) (`fallback` by default).
    In `fallback` mode the real state or output wins and the mock is used only when the component is
    not provisioned or the output is missing.
  - `--use-mocks=fallback` or `--use-mocks=always`: mocks are on, overriding the configured mode for this run.
    The `always` value resolves `!terraform.state` and `!terraform.output` lookups from mocks only, without initializing the referenced components, authenticating, or reading their backends. The plan itself still initializes this component and uses its own backend and provider credentials.
  Matching is case-insensitive, and any other value is an error. Attach the mode with `=`: a bare
  `--use-mocks` takes no value, so `--use-mocks always` leaves `always` as a positional argument and
  Atmos reports an error with a hint.

  Default: off. Requires YAML function processing to remain enabled.
  Accepted only by `atmos terraform plan` and `atmos describe component`; every other `atmos terraform`
  subcommand (for example `apply`, `deploy`, and `destroy`) rejects it, and also fails if `ATMOS_USE_MOCKS`
  is set in the environment, so unset the variable before running them.
  With `--all` or `--affected`, the flag is passed through to each component.
- **`--stack` / `-s` (required)**

  Atmos stack name where the component is defined.
- **`--skip-planfile` (optional)**

  Skip writing the plan to a file. When set, Atmos will not pass the `-out` flag to Terraform.

  This is useful when:
  - Using Terraform Cloud (which doesn't support `-out`)
  - Running quick plan checks without saving the output
  - Running in CI/CD environments where planfiles aren't needed
  ```shell
  atmos terraform plan vpc -s dev --skip-planfile
  ```
- **`--affected` (optional)**

  Plan only affected components based on changes in the repository. This is a global operation that identifies and plans all components affected by recent changes across all stacks.
  ```shell
  # Plan only affected components across all stacks
  atmos terraform plan --affected
  ```
- **`--all` (optional)**

  Plan all components in all stacks (use with caution).
  ```shell
  atmos terraform plan --all
  ```
- **`--dry-run` (optional)**

  Show what would be executed without actually running the plan.
  ```shell
  atmos terraform plan vpc -s dev --dry-run
  ```
- **`--skip-init` (optional)**

  Skip running `terraform init` before planning.
  ```shell
  atmos terraform plan vpc -s dev --skip-init
  ```
- **`--init-mode` (optional)**

  Override [`init.mode`](/cli/configuration/components/terraform#configuration-reference) for this invocation: `auto` (default, skip init when nothing relevant changed), `always`, or `never` (disables the ordinary implicit init, but unlike `--skip-init` does not suppress the forced reconfigure init that `atmos terraform workspace select`/`new` needs).
  ```shell
  atmos terraform plan vpc -s dev --init-mode=always
  ```
- **`--init-reconfigure` (optional)**

  Override [`init.reconfigure`](/cli/configuration/components/terraform#configuration-reference) for this invocation: `auto` (default), `always`, or `never`.
  ```shell
  atmos terraform plan vpc -s dev --init-reconfigure=always
  ```
- **`--init-upgrade` (optional)**

  Override [`init.upgrade`](/cli/configuration/components/terraform#configuration-reference) for this invocation: `auto` (default), `always`, or `never`.
  ```shell
  atmos terraform plan vpc -s dev --init-upgrade=always
  ```
- **`--process-templates` (optional)**

  Enable/disable Go template processing in Atmos stack manifests.

  Default: `true`
  ```shell
  atmos terraform plan vpc -s dev --process-templates=false
  ```
- **`--ui` (optional)**

  Enable streaming UI mode for real-time resource status display. Shows a Docker-build-style progress view with spinners, progress bar, and resource states.

  The UI automatically disables when output is piped, in CI environments, or when running unsupported commands.

  `--ui` errors when combined with `--max-concurrency` greater than `1`, since concurrently-scheduled components can't share one terminal for their full-screen UI sessions. Use `--max-concurrency 1` (the default) with `--ui`, or drop `--ui` to run concurrently.
  ```shell
  atmos terraform plan vpc -s dev --ui
  ```
  Use `--ui=false` to explicitly disable when enabled by config.
- **`--ci` (optional)**

  Enable CI mode for automated pipelines. When enabled, Atmos writes job summaries, CI output variables, and status checks based on the [`ci` configuration](/cli/configuration/ci) in `atmos.yaml`.

  CI mode is auto-detected when `CI=true` or `GITHUB_ACTIONS=true` environment variables are set. Use this flag to explicitly enable CI mode in environments where auto-detection is not available.

  **Environment variables:** `ATMOS_CI`, `CI`
  ```shell
  atmos terraform plan vpc -s dev --ci
  ```

## Native Terraform Flags

The `atmos terraform plan` command supports all native `terraform plan` flags. To pass native Terraform flags, you have two options:

1. **Direct flags** - Pass Terraform flags directly if they don't conflict with Atmos flags
2. **Double-dash separator** - Use `--` to explicitly separate Atmos flags from Terraform flags

:::tip Using the Double-Dash Separator
The `--` separator is a common Unix convention that indicates "end of options". Everything after `--` is passed directly to Terraform without interpretation by Atmos. This is useful when:

- You want to ensure a flag is passed to Terraform, not Atmos
- You're using flags that might conflict with Atmos flags
- You want to be explicit about which tool receives which flags

**Example:**

```shell
atmos terraform plan vpc -s dev -- -refresh=false -out=my-custom.tfplan
```

:::

Some commonly used native flags include:

- **`-out=FILE`**

  Write the plan to a file at the specified path. This is the standard Terraform flag for specifying a custom planfile location.
  ```shell
  atmos terraform plan vpc -s dev -out=my-plan.tfplan
  ```
- **`-destroy`**

  Create a plan to destroy all resources.
  ```shell
  atmos terraform plan vpc -s dev -destroy
  ```
- **`-target=RESOURCE`**

  Plan only specific resources. Can be specified multiple times.
  ```shell
  atmos terraform plan vpc -s dev -target=aws_subnet.private -target=aws_route_table.private
  ```
- **`-var 'NAME=VALUE'`**

  Set a variable value. Can be specified multiple times.
  ```shell
  atmos terraform plan vpc -s dev -var="instance_count=3" -var="environment=staging"
  ```
- **`-refresh-only`**

  Create a plan to update the state to match remote systems.
  ```shell
  atmos terraform plan vpc -s dev -refresh-only
  ```

### Default Locking and Concurrency Flags

Instead of retyping flags like `-lock-timeout` on every invocation, declare a default
in [`components.terraform.flags`](/cli/configuration/components/terraform#flags) — globally
in `atmos.yaml`, per stack, or per component. `plan` supports all five flags
(`lock_timeout`, `lock`, `parallelism`, `refresh`, `compact_warnings`); a native flag typed
directly on the command line (as shown above) always wins over a declared default.

## Multi-Component Operations

Execute `terraform plan` across multiple components using filtering flags. All flags can be combined with `--dry-run` to preview what would be executed.

### Plan All Components

```shell
# Plan all components in all stacks
atmos terraform plan --all

# Plan all components in a specific stack
atmos terraform plan --all --stack prod
atmos terraform plan --stack prod
```

### Plan Affected Components

Plan only components affected by changes in the current branch (requires git):

```shell
# Plan affected components in all stacks
atmos terraform plan --affected

# Plan affected components in a specific stack
atmos terraform plan --affected --stack prod

# Include dependent components (components that depend on affected components)
atmos terraform plan --affected --include-dependents

# Clone the target reference instead of checking it out
atmos terraform plan --affected --clone-target-ref=true
```

### Plan Specific Components

```shell
# Plan specific components in all stacks
atmos terraform plan --components vpc,eks

# Plan specific components in a specific stack
atmos terraform plan --components vpc,eks --stack prod
```

### Plan Components by Query

Filter components using [YQ](https://mikefarah.gitbook.io/yq) expressions against component configuration:

```shell
# Plan components where team tag equals "eks"
atmos terraform plan --query '.vars.tags.team == "eks"'

# Plan components in a specific account
atmos terraform plan --query '.settings.context.account_id == 12345'

# Combine with stack filter
atmos terraform plan --query '.vars.tags.team == "eks"' --stack prod
```

### Plan Components by Tags and Labels

Filter components by `metadata.tags`/`metadata.labels`. These flags compose with `--all`/`--affected`/`--components`/`--query` to narrow the selected set further, rather than being mutually exclusive with them:

```shell
# Plan components tagged production or tier-1 (matches any)
atmos terraform plan --tags production,tier-1

# Plan components labeled cost-center=platform (matches all given labels)
atmos terraform plan --labels cost-center=platform

# Narrow an --affected run to only production-tagged components
atmos terraform plan --affected --tags production
```

### Include Dependencies and Dependents

Selector flags choose the seed set; `--include-dependencies` and `--include-dependents` expand it through the dependency graph. Expanded components are planned even when they do not match the selectors — they are prerequisites (or dependents) of what was selected. Prerequisites can live in other stacks, so `--include-dependencies` with `-s dev` legitimately plans prerequisite components outside the `dev` stack:

```shell
# Plan dev-labeled components plus everything they depend on
atmos terraform plan --labels=env=dev --include-dependencies

# Bound the expansion to direct dependencies only
atmos terraform plan --labels=env=dev --include-dependencies=1

# Plan a stack plus everything that depends on it, up to two levels out
atmos terraform plan -s dev --include-dependents=2
```

Pass the depth with `=` (for example, `--include-dependencies=2`); a space-separated value is not bound to the flag. The bare flag expands without a depth limit, and `true`/`false` values are accepted for backward compatibility.

### Multi-Component Flags

- **`--all`**
  Plan all components in all stacks (or specified stack with 
  `--stack`
  ).
- **`--affected`**
  Plan components affected by git changes in dependency order. Supports all flags from 
  [`atmos describe affected`](/cli/commands/describe/affected)
  .
- **`--components`**
  Plan specific components by name (comma-separated or repeated flag).
- **`--query`**
  Plan components matching a YQ expression. All Atmos sections are available: 
  `vars`
  , 
  `settings`
  , 
  `env`
  , 
  `metadata`
  , etc.
- **`--tags`**
  Filter by tags (comma-separated, matches any): 
  `--tags=production,tier-1`
  . Composes with 
  `--all`
  /
  `--affected`
  /
  `--components`
  /
  `--query`
   to narrow the selected set further; cannot be combined with a single component argument.
- **`--labels`**
  Filter by labels (comma-separated 
  `key=value`
   or 
  `key:value`
   pairs, matches all): 
  `--labels=cost-center=platform,compliance=sox`
  . Composes with 
  `--all`
  /
  `--affected`
  /
  `--components`
  /
  `--query`
  /
  `--tags`
  ; cannot be combined with a single component argument.
- **`--include-dependencies`**
  Also plan everything the selected components depend on (their prerequisites), in dependency order — even when the prerequisites live in other stacks or do not match the selectors. Accepts an optional depth: the bare flag expands the full dependency chain, while 
  `--include-dependencies=1`
   bounds it to direct dependencies. Requires a multi-component selection.
  Environment variable: 
  `ATMOS_INCLUDE_DEPENDENCIES`
- **`--include-dependents`**
  Also plan everything that depends on the selected components, in dependency order. Works with any multi-component selection (
  `--all`
  , 
  `--components`
  , 
  `--query`
  , 
  `--stack`
  , 
  `--tags`
  , 
  `--labels`
  , 
  `--affected`
  ). Accepts an optional depth: the bare flag expands the full dependent chain, while 
  `--include-dependents=2`
   bounds it to two levels.
  Environment variable: 
  `ATMOS_INCLUDE_DEPENDENTS`
- **`--ref`**
  Git reference to compare against (branch or tag). Default: 
  `refs/remotes/origin/HEAD`
  .
- **`--sha`**
  Git commit SHA to compare against.
- **`--clone-target-ref`**
  Clone the target reference instead of checking it out locally.

## CI Integration

> ⚠️ Experimental

When running in CI mode (`--ci` flag or auto-detected), Atmos produces rich CI artifacts:

- **Job summaries** with resource badges, collapsible diffs, and warnings written to `$GITHUB_STEP_SUMMARY`
- **Output variables** (`has_changes`, `has_errors`, `exit_code`, etc.) written to `$GITHUB_OUTPUT`
- **Status checks** showing plan progress and results (requires `ci.checks.enabled: true`)
- **PR plan-summary comments** when `ci.comments.enabled: true`, the run is for a pull request, and
  the workflow grants `pull-requests: write`; comments reuse the job-summary template and are
  updated by default on later runs for the same command, component, and stack

```shell
# In GitHub Actions (auto-detected)
atmos terraform plan vpc -s dev

# Explicit CI mode
atmos terraform plan vpc -s dev --ci
```

:::info
See [CI Configuration](/cli/configuration/ci) for full configuration options including custom templates, status checks, and output variables. See [CI Pull Request Comments](/cli/configuration/ci/comments) to opt into plan-summary comments.
:::

## Related Commands

- [`atmos terraform apply`](/cli/commands/terraform/apply) - Apply the changes from a plan
- [`atmos terraform deploy`](/cli/commands/terraform/deploy) - Deploy with auto-approval
- [`atmos terraform plan-diff`](/cli/commands/terraform/plan-diff) - Compare two plan files

## Configuration

Configure default behavior for `terraform plan` in your `atmos.yaml`:

```yaml
components:
  terraform:
    plan:
      # Skip generating planfiles by default (useful for Terraform Cloud)
      skip_planfile: false
```

This can also be set using the environment variable:

```shell
export ATMOS_COMPONENTS_TERRAFORM_PLAN_SKIP_PLANFILE=true
```

:::info
See [Terraform Planfiles](/components/terraform/planfiles) for a comprehensive guide on working with planfiles in Atmos.
:::
