# Terraform Configuration

import File from "@site/src/components/File";
import Intro from "@site/src/components/Intro";
import DocCardList from "@theme/DocCardList";

<Intro>
  Configure how Atmos executes Terraform and OpenTofu commands, including the
  base path for components, auto-approve behavior, backend file generation, and
  initialization options.
</Intro>

:::note Disambiguation
The term "Terraform" is used in this documentation to refer to generic concepts such as providers, modules, stacks, the HCL-based domain-specific language and its interpreter. Atmos works with both Terraform and OpenTofu.
:::

## Configuration

<File title="atmos.yaml">
```yaml
components:
  terraform:
    # Executable to run (terraform, tofu, or absolute path)
    command: terraform

    # Base path to Terraform components
    base_path: components/terraform

    # Automatically add -auto-approve to apply commands
    apply_auto_approve: false

    # Run terraform init before deploy
    deploy_run_init: true

    # Add -reconfigure to init commands
    init_run_reconfigure: true

    # Generate backend.tf.json from stack configuration
    auto_generate_backend_file: true

    # Generate files from the `generate` section before terraform commands
    auto_generate_files: false

    # Init command options
    init:
      pass_vars: false

    # Plan command options
    plan:
      skip_planfile: false

    # Provider plugin caching (enabled by default)
    plugin_cache: true
    plugin_cache_dir: ""  # Uses ~/.cache/atmos/terraform/plugins by default

    # Registry cache proxy (disabled by default)
    cache:
      enabled: false
      location: ""  # Uses ~/.cache/atmos/terraform/registry by default

    # Interactive shell configuration
    shell:
      prompt: "Terraform Shell"

```
</File>

## Configuration Reference

<dl>
  <dt>`command`</dt>
  <dd>
    Specifies the executable to run for Terraform commands. Defaults to `terraform`.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_COMMAND`
    **Command-line flag:** `--terraform-command`

    Examples:
    - `terraform` - Use Terraform from PATH
    - `tofu` - Use OpenTofu from PATH
    - `/usr/local/bin/terraform-1.8` - Use specific version
    - `/usr/local/bin/tofu-1.7.1` - Use specific OpenTofu version
  </dd>

  <dt>`base_path`</dt>
  <dd>
    Directory containing Terraform component directories. Supports absolute and relative paths.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_BASE_PATH`
    **Command-line flag:** `--terraform-dir`
  </dd>

  <dt>`apply_auto_approve`</dt>
  <dd>
    When `true`, Atmos adds `-auto-approve` to `terraform apply` commands, skipping the confirmation prompt.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE`
    **Default:** `false`
  </dd>

  <dt>`deploy_run_init`</dt>
  <dd>
    When `true`, Atmos runs `terraform init` before executing [`atmos terraform deploy`](/cli/commands/terraform/deploy).

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_DEPLOY_RUN_INIT`
    **Command-line flag:** `--deploy-run-init`
    **Default:** `true`
  </dd>

  <dt>`init_run_reconfigure`</dt>
  <dd>
    When `true`, Atmos adds `-reconfigure` to `terraform init` commands, updating backend configuration.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_INIT_RUN_RECONFIGURE`
    **Command-line flag:** `--init-run-reconfigure`
    **Default:** `true`
  </dd>

  <dt>`auto_generate_backend_file`</dt>
  <dd>
    When `true`, Atmos generates `backend.tf.json` from stack configuration before running Terraform commands.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE`
    **Command-line flag:** `--auto-generate-backend-file`
    **Default:** `true`
  </dd>

  <dt>`auto_generate_files`</dt>
  <dd>
    When `true`, Atmos generates files from the [`generate`](/stacks/generate) section in stack configuration before running Terraform commands.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_FILES`
    **Default:** `false`
  </dd>

  <dt>`init.pass_vars`</dt>
  <dd>
    When `true`, Atmos passes the generated varfile to `terraform init` using `--var-file`. This is primarily useful with OpenTofu, which supports [passing varfiles to init](https://opentofu.org/docs/cli/commands/init/#general-options) for dynamic backend configuration.

    This also applies to the implicit `init` that Atmos runs while resolving a component referenced through [`!terraform.output`](/functions/yaml/terraform.output) or [`atmos.Component`](/functions/template/atmos.Component) — its vars are forwarded as `TF_VAR_*` environment variables so that modules with init-time variable dependencies (for example, a module `version` bound to a `var`) can initialize.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_INIT_PASS_VARS`
    **Command-line flag:** `--init-pass-vars`
    **Default:** `false`
  </dd>

  <dt>`plan.skip_planfile`</dt>
  <dd>
    When `true`, Atmos skips creating a plan file during `terraform plan`. The plan output is shown but not saved.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_PLAN_SKIP_PLANFILE`
    **Command-line flag:** `--skip-planfile`
    **Default:** `false`
  </dd>

  <dt>`planfiles`</dt>
  <dd>
    Configures [planfile storage](/ci/planfile-storage) and
    [drift verification](/components/terraform/planfiles#drift-verification) for CI pipelines.
    Storage is opt-in: when this section is absent, planfile upload, download, and verification are
    skipped (and an explicit `--verify-plan` request errors, since there is no stored plan to verify
    against).

    ```yaml
    components:
      terraform:
        planfiles:
          stores:
            github:
              type: github/artifacts
          priority: [github]
          verify: fail
    ```

    <dl>
      <dt>`planfiles.stores`</dt>
      <dd>Named store definitions. Each store has a `type` (`github/artifacts`, `aws/s3`, or `local/dir`) and backend-specific `options`.</dd>

      <dt>`planfiles.default`</dt>
      <dd>Name of the store to use when no priority list is set.</dd>

      <dt>`planfiles.priority`</dt>
      <dd>Ordered list of store names to try in turn for upload and download.</dd>

      <dt>`planfiles.verify`</dt>
      <dd>
        Drift-verification behavior on `deploy`: `fail` (default under CI), `warn`, or `off`.
        Precedence is **CLI flag (`--verify-plan` / `--verify-plan=false`) > config > CI default**.

        **Environment variable (per-run override):** `ATMOS_TERRAFORM_VERIFY_PLAN`
      </dd>

      <dt>`planfiles.required`</dt>
      <dd>Whether a stored planfile **must exist** for `deploy` to proceed. Unset, it tracks `verify` strictness (required when verification resolves to `fail`).</dd>
    </dl>

    See [Planfile Storage](/ci/planfile-storage) for backend configuration and
    [Terraform Planfiles](/components/terraform/planfiles#drift-verification) for verification
    semantics.
  </dd>

  <dt>`plugin_cache`</dt>
  <dd>
    When `true`, Atmos enables Terraform provider plugin caching by automatically setting `TF_PLUGIN_CACHE_DIR`. This improves performance by reusing downloaded providers across components, reducing init times and network bandwidth.

    This is Terraform's **own** provider cache and is independent of the [registry cache](#cache) (`cache`). The plugin cache stores provider plugins that Terraform manages itself; the registry cache is an Atmos-managed proxy that caches both provider *and* module registry traffic. The two are separate layers and can be used together.

    When caching is enabled, Atmos also sets `TF_PLUGIN_CACHE_MAY_BREAK_DEPENDENCY_LOCK_FILE=true` as required by Terraform.

    If `TF_PLUGIN_CACHE_DIR` is already set in your environment or via the global `env:` section in `atmos.yaml`, Atmos does not override it—you manage your own cache.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_PLUGIN_CACHE`
    **Default:** `true`
  </dd>

  <dt>`plugin_cache_dir`</dt>
  <dd>
    Custom directory path for the Terraform plugin cache. If empty (default), Atmos uses the XDG cache directory: `~/.cache/atmos/terraform/plugins`.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_PLUGIN_CACHE_DIR`
    **Default:** `""` (uses XDG cache directory)
  </dd>

  <dt>`auto_provision_workdir_for_outputs`</dt>
  <dd>
    When `true` (default), Atmos automatically provisions the JIT working directory
    for components with `provision.workdir.enabled: true` before running
    `terraform init` during `!terraform.output` or `atmos.Component` evaluation.
    This enables cross-component output references to work on any machine, including
    fresh CI runners where the workdir has not been created yet.

    Set to `false` to disable auto-provisioning. `terraform init` will still run,
    but only if the workdir has already been created by a prior deploy; on a fresh
    machine with no prior workdir it will fail.

    For state-only reads, prefer `!terraform.state` — it reads the state file
    directly with no `terraform init`, no workdir provisioning step, and no
    terraform binary required.

    **Environment variable:** `ATMOS_COMPONENTS_TERRAFORM_AUTO_PROVISION_WORKDIR_FOR_OUTPUTS`
    **Default:** `true`
  </dd>

  <dt>`shell.prompt`</dt>
  <dd>
    Custom prompt to display when running [`atmos terraform shell`](/cli/commands/terraform/shell).
  </dd>
</dl>

## Using OpenTofu

To use OpenTofu instead of Terraform, set the `command` to `tofu`:

<File title="atmos.yaml">
```yaml
components:
  terraform:
    command: tofu
    base_path: components/terraform
```

</File>

OpenTofu supports additional features like passing variables to `init` for dynamic backend configuration:

<File title="atmos.yaml">
```yaml
components:
  terraform:
    command: tofu
    init:
      pass_vars: true
```
</File>

## CLI Configuration (`rc`) {#rc}

The `rc` section declares the Terraform/OpenTofu CLI configuration (`.terraformrc` / `.tofurc`). Atmos renders it and exposes it to the subprocess via `TF_CLI_CONFIG_FILE` and `TOFU_CLI_CONFIG_FILE` — no hand-managed dotfiles. It is a **near-opaque passthrough**: keys map directly to CLI-config directives, so new directives work without an Atmos release.

<dl>
  <dt><code>enabled</code></dt>
  <dd>Enable rendering of the CLI configuration. Defaults to <code>false</code>.</dd>
  <dt>(remaining keys)</dt>
  <dd>Rendered verbatim into Terraform's native CLI config (HCL): <code>provider_installation</code>, <code>host</code>, <code>credentials</code>, <code>plugin_cache_dir</code>, etc.</dd>
</dl>

```yaml
components:
  terraform:
    rc:
      enabled: true
      provider_installation:
        - network_mirror:
            url: "https://terraform-mirror.example.com/"
        - direct:
            exclude:
              - "registry.terraform.io/hashicorp/*"
```

If you already manage your own CLI config (via `TF_CLI_CONFIG_FILE`, `TOFU_CLI_CONFIG_FILE`, or the legacy `TERRAFORM_CONFIG`), Atmos detects it and defers to you.

## Registry Cache (`cache`) {#cache}

The `cache` section enables the [Terraform registry cache](/cli/commands/terraform/cache) — transparent provider and module caching via an ephemeral local network-mirror proxy. It is execution-environment (runner) configuration that merges through the stack hierarchy.

This is **not** the same as Terraform's [`plugin_cache`](#configuration-reference): the registry cache is an Atmos-managed proxy that caches both provider *and* module registry traffic (default root `~/.cache/atmos/terraform/registry`), whereas `plugin_cache` is Terraform's own provider plugin cache (`~/.cache/atmos/terraform/plugins`). They are independent layers.

<dl>
  <dt><code>enabled</code></dt>
  <dd>
    Enable the registry cache. Defaults to <code>false</code>.

    <strong>Environment variable:</strong> <code>ATMOS_COMPONENTS_TERRAFORM_CACHE_ENABLED</code>
  </dd>
  <dt><code>location</code></dt>
  <dd>
    Cache root. Defaults to the XDG cache directory under <code>terraform/registry</code>.

    <strong>Environment variable:</strong> <code>ATMOS_COMPONENTS_TERRAFORM_CACHE_LOCATION</code>
  </dd>
  <dt><code>backend.type</code></dt>
  <dd>Storage backend. <code>filesystem</code> (default).</dd>
  <dt><code>metadata_ttl</code></dt>
  <dd>Time-to-live for registry metadata (Go duration). Defaults to <code>24h</code>.</dd>
  <dt><code>stale_while_revalidate</code></dt>
  <dd>Window during which stale metadata may be served while revalidating (Go duration). Defaults to <code>168h</code>.</dd>
  <dt><code>mirror.enabled</code></dt>
  <dd>Express fleet pre-seeding policy. The <a href="/cli/commands/terraform/cache/mirror"><code>cache mirror</code></a> command runs regardless. Defaults to <code>false</code>.</dd>
</dl>

Target platforms are configured at the project level via [`platforms`](#platforms) (not under `cache`), since the same list also drives multi-platform lock completion.

```yaml
components:
  terraform:
    platforms:
      - linux_amd64
      - darwin_arm64
      - windows_amd64
    cache:
      enabled: true
      metadata_ttl: 24h
      stale_while_revalidate: 168h
```

Manage the cache with [`atmos terraform cache list|stats|prune|delete|mirror`](/cli/commands/terraform/cache).

## Platforms (`platforms`) {#platforms}

`components.terraform.platforms` is the list of target platforms a project builds for, as `<os>_<arch>` (e.g. `linux_amd64`, `darwin_arm64`). A single list drives two things:

<dl>
  <dt>Eager pre-seeding</dt>
  <dd>The lazy proxy only caches the platform Terraform requests at run time (your host's). Run <a href="/cli/commands/terraform/cache/mirror"><code>atmos terraform cache mirror</code></a> to pre-fetch every platform in <code>platforms</code> into the same cache directory — for mixed CI/developer fleets or air-gapped bundles.</dd>
  <dt>Complete lock files</dt>
  <dd>When a customized provider installation method is active (Terraform's default <a href="#configuration-reference"><code>plugin_cache</code></a>, or the registry <a href="#cache"><code>cache</code></a>), <code>init</code> writes a <code>.terraform.lock.hcl</code> with checksums for only the host platform and warns <em>"Incomplete lock file information for providers"</em>. With <code>platforms</code> declared, Atmos runs <code>providers lock</code> after init to complete the lock for every platform, so a committed lock installs cleanly across a fleet.</dd>
</dl>

```yaml
components:
  terraform:
    platforms:
      - linux_amd64
      - darwin_arm64
      - windows_amd64
```

For **ephemeral or vendored** components ([`provision.workdir`](/cli/commands/terraform/workdir) or a [`source:`](/vendor/)) the canonical `.terraform.lock.hcl` has no committable home, so Atmos keeps the committed lock per instance as `.<stack>-<component>.terraform.lock.hcl` — restored into the working directory before `init` and persisted after. Keep canonical `**/.terraform.lock.hcl` ignored and un-ignore `!**/.*-*.terraform.lock.hcl` in `.gitignore`. Plain in-repo components keep committing the canonical lock as usual.

## Generated Files

When `auto_generate_backend_file` is enabled, Atmos generates a `backend.tf.json` file in each component directory. Add this to your `.gitignore`:

```gitignore
# Atmos generated files
backend.tf.json
```

## Related Commands

<DocCardList
  items={[
    {
      type: "link",
      href: "/cli/commands/terraform/usage",
      label: "atmos terraform",
      description: "Execute Terraform/OpenTofu commands",
    },
    {
      type: "link",
      href: "/cli/commands/terraform/plan",
      label: "atmos terraform plan",
      description: "Generate and show execution plan",
    },
    {
      type: "link",
      href: "/cli/commands/terraform/apply",
      label: "atmos terraform apply",
      description: "Apply infrastructure changes",
    },
    {
      type: "link",
      href: "/cli/commands/terraform/deploy",
      label: "atmos terraform deploy",
      description: "Run init, plan, and apply in sequence",
    },
    {
      type: "link",
      href: "/cli/commands/terraform/shell",
      label: "atmos terraform shell",
      description: "Open an interactive shell",
    },
    {
      type: "link",
      href: "/cli/commands/terraform/generate/backends",
      label: "atmos terraform generate backends",
      description: "Generate backend configuration files",
    },
    {
      type: "link",
      href: "/cli/commands/terraform/generate/varfiles",
      label: "atmos terraform generate varfiles",
      description: "Generate variable files",
    },
    {
      type: "link",
      href: "/cli/commands/terraform/generate/files",
      label: "atmos terraform generate files",
      description: "Generate auxiliary configuration files",
    },
  ]}
/>

## Related

- [Component Configuration Overview](/cli/configuration/components)
- [Stack Configuration](/cli/configuration/stacks)
- [Terraform Components](/components/terraform)
- [Terraform Backend](/stacks/backend)
- [Generate Terraform Files](/stacks/generate)
