# Component Output Mocks

Declare literal outputs on a component and opt into using them for
[`!terraform.state`](/functions/yaml/terraform.state) and
[`!terraform.output`](/functions/yaml/terraform.output) lookups during local plans or configuration inspection.
By default, mocks are fallbacks: a real value wins when it exists, and the mock fills in only when it doesn't.

## Usage

Declare `mocks` on the component that produces the outputs:

**File:** `stacks/dev.yaml`

```yaml
components:
  terraform:
    vpc:
      mocks:
        vpc_id: vpc-local
        private_subnet_ids: [subnet-a, subnet-b]
    app:
      vars:
        vpc_id: !terraform.state vpc vpc_id
        first_subnet: !terraform.output vpc '.private_subnet_ids[0]'
```

Enable mock lookups explicitly:

```shell
atmos describe component app -s dev --use-mocks
atmos terraform plan app -s dev --use-mocks
```

When `vpc` has not been provisioned, the lookups return `vpc-local` and `subnet-a`. After
`atmos terraform apply vpc -s dev`, the same commands return the real `vpc_id` and subnet
from state. To always use the mocks, even when state exists, pass `--use-mocks=always`.

:::warning Attach the mode with an equals sign
A bare `--use-mocks` takes no value, so `--use-mocks always` leaves `always` behind as a positional
argument and does not select the mode. When the mode word follows the component, Atmos reports
this with an error and a hint. Write
`--use-mocks=always`.
:::

Running the app's plan can still require its own provider credentials and infrastructure access.

## Resolution modes

The `components.terraform.mocks.mode` setting decides how `--use-mocks` treats real state.
Configure it once in `atmos.yaml`:

**File:** `atmos.yaml`

```yaml
components:
  terraform:
    mocks:
      mode: fallback  # fallback (default) | always
```

### Fallback mode

In `fallback` mode Atmos runs the real lookup first, including authentication and the backend read.
It uses the component's `mocks` only when the lookup misses in a recoverable way: the referenced
component's state is not provisioned, or the requested output is missing.

With the `vpc` example above:

| Situation | Result for `!terraform.state vpc vpc_id` |
|---|---|
| `vpc` applied, output `vpc_id` is `vpc-0abc` | `vpc-0abc` (the mock is ignored) |
| `vpc` never applied | `vpc-local` (from `mocks`) |
| `vpc` applied, but it has no `vpc_id` output | `vpc-local` (from `mocks`) |
| `vpc` never applied, `vpc` declares no matching mock | The normal not-provisioned error for `!terraform.state`; `null` for `!terraform.output`, the same as without mocks |
| `vpc` applied, no `vpc_id` output, and no `vpc_id` mock | `null`, the same as without mocks |
| Backend returns an access-denied or network error | The error. Mocks never hide it |

When the real lookup for a component that declares `mocks` fails with an error that is not
recoverable (credentials, network, backend, Terraform initialization, or a missing Terraform
binary), the error includes a hint to use
`--use-mocks=always` or `components.terraform.mocks.mode: always` for mocks-only resolution.
Use `always` for lookups on machines that have no credentials or no Terraform installed, such as
CI jobs that only inspect configuration with `atmos describe component`.

The precedence is: real value, then mock, then a YQ `//` default, then the original error.
A `//` default in the expression is therefore the last resort, not a replacement for the mock:

```yaml
vars:
  vpc_id: !terraform.state vpc '.vpc_id // "vpc-default"'
```

Here the value is the real `vpc_id` when it exists, `vpc-local` when only the mock exists, and
`vpc-default` when neither exists.

#### Map outputs are merged

Mocks are deep-merged under the real outputs. Every value present in real state wins, and a mock
fills only the keys that are missing from a real map output. Suppose the real `config` output is
`{ a = 1 }` and the mock is:

```yaml
components:
  terraform:
    vpc:
      mocks:
        config: {a: 0, b: 2}
```

Then `.config.a` is the real `1`, `.config.b` is `2` from the mock, and `.config` resolves to
`{a: 1, b: 2}`.

Lists and scalars are never merged element by element. A real list replaces the mock list
wholesale, and a real scalar replaces the mock scalar.

:::note Outputs that are null in state
Terraform does not record outputs whose value is `null` in state. In fallback mode an output that is
`null` in a provisioned component is therefore indistinguishable from a missing output, and it
resolves to the mock. Don't declare a mock for an output that can legitimately be `null`, or use
`--use-mocks=always` when that matters.
:::

### Always mode

In `always` mode lookups resolve from `mocks` and nothing else. Atmos does not initialize
Terraform, authenticate, read a backend, or use the state caches for those lookups, so the
result is the same on every machine regardless of what has been deployed.

```shell
atmos describe component app -s dev --use-mocks=always
```

Use `always` when lookups must be hermetic, for example `atmos describe component` in CI jobs with
no cloud credentials or without Terraform installed. A plan with `--use-mocks=always` still
initializes and plans the component itself, so it needs Terraform and that component's own backend
and provider access; only the lookups it makes are hermetic.
In this mode a missing `mocks` map or an undeclared output is an error, because there is no real
value to fall back to. A YQ `//` default still applies:

```yaml
vars:
  vpc_id: !terraform.state vpc '.vpc_id // "vpc-default"'
```

### Edition default

The default mode depends on the project's [config edition](/cli/configuration/edition).
Unpinned projects, and projects pinned to an edition on or after 2026-10-01, use `fallback`.
Projects pinned to an earlier edition use `always`, which is how bare `--use-mocks` behaved
before the setting existed. Set `components.terraform.mocks.mode` explicitly to choose either
mode regardless of the pin.

## Configuration Reference

- **`mocks`**
  A map of output names to literal values on the producer component. Templates and YAML
  functions inside the map are not evaluated. The map follows component inheritance and deep merging.
  Explicit 
  `null`
   values are valid.
- **`--use-mocks`**

  Turns on mock lookups for `atmos terraform plan` and `atmos describe component`. Every other
  `atmos terraform` subcommand (for example `apply`, `deploy`, and `destroy`) rejects the flag.
  `atmos terraform plan --all` and `--affected` pass it through to each component. YAML function
  processing must remain enabled. Accepted values (matching is case-insensitive):
  - Absent, empty, or a false boolean (`false`, `0`, `f`): mocks are off and lookups use real state and outputs.
  - Bare `--use-mocks` or a true boolean (`true`, `1`, `t`): mocks are on, using the
    resolved `components.terraform.mocks.mode`.
  - `fallback` or `always`: mocks are on, overriding `components.terraform.mocks.mode` for this run.
  Any other value is an error. Attach the value with `=`, as in `--use-mocks=always`; a bare
  `--use-mocks` takes no value, so `--use-mocks always` leaves `always` as a positional argument and
  Atmos reports it as an error with a hint.

  **Default:** off
- **`ATMOS_USE_MOCKS`**

  Environment equivalent of `--use-mocks`, with the same accepted values. Only `atmos terraform plan`
  reads it; `atmos describe component` ignores it, so pass `--use-mocks` there. If `ATMOS_USE_MOCKS`
  is exported in a shell or CI environment, every `atmos terraform` subcommand other than `plan`
  (for example `apply`, `deploy`, and `destroy`) fails with an error that names the variable. Unset it
  before running those commands.
- **`components.terraform.mocks.mode`**

  Either `fallback` or `always`, as described in [Resolution modes](#resolution-modes). The value in
  `atmos.yaml` is case-insensitive (`Always` works). An invalid value, whether in `atmos.yaml` or in
  `ATMOS_COMPONENTS_TERRAFORM_MOCKS_MODE`, fails at configuration load for every command, not only
  when a `--use-mocks` lookup runs. The
  default is `fallback` for unpinned projects and projects pinned to a
  [config edition](/cli/configuration/edition) on or after 2026-10-01, and `always` for
  projects pinned to an earlier edition. The effective value resolves in this order (highest
  wins): the `--use-mocks=<mode>` flag, the `ATMOS_COMPONENTS_TERRAFORM_MOCKS_MODE` environment
  variable, `atmos.yaml`, then the edition-aware default. See the
  [Terraform configuration reference](/cli/configuration/components/terraform) for the full field entry.

## Limits

Without `--use-mocks`, lookups use their normal state and output source. This feature does
not simulate providers or provision resources. See the
[component mocks example](/examples/terraform-component-mocks) for a producer and consumer configuration.
