# Provider Generation

Terraform utilizes plugins known as [providers](https://developer.hashicorp.com/terraform/language/providers) for
communication with cloud providers, SaaS providers, and various APIs.

In order for Terraform to install these providers, the corresponding Terraform configurations need to
explicitly state what providers are required. Furthermore, certain providers require additional configuration, such as
specifying endpoint URLs or cloud regions, before they can be used.

## Provider Configuration in Terraform

When working with Terraform, you specify provider configurations in your Terraform code. This involves
declaring which providers your infrastructure requires and providing any necessary configuration parameters.
These parameters may include endpoint URLs, cloud regions, access credentials, or any other provider-specific
configuration parameters.

To declare a provider in Terraform, use a `provider` block within your Terraform configuration files,
usually in a `providers.tf` file in the component (a.k.a. root module) directory.
The `provider` block specifies the provider type and all the necessary configuration parameters.

Here's an AWS provider configuration example for a `vpc` component. The provider config is defined in
the `components/terraform/vpc/providers.tf` file:

**File:** `components/terraform/vpc/providers.tf`

```hcl
provider "aws" {
    region = "us-east-2"
    assume_role {
      role_arn: "IAM Role ARN"
    }
  }
```

In this example, the `aws` provider block includes the region and IAM role required for Terraform to communicate
with the AWS services.

By correctly defining provider configurations in your Terraform code, you ensure that Terraform can seamlessly install,
configure, and use the necessary plugins to manage your infrastructure across various cloud and services.

## Provider Configuration and Overrides in Atmos Manifests

Atmos allows you to define and override provider configurations using the `providers` section in Atmos stack manifests.
The section can be defined globally for the entire organization, OU/tenant, account, region, or per component.

For example, the `providers` section at the global scope can look like this:

**File:** `stacks/orgs/acme/_defaults.yaml`

```yaml
terraform:
  providers:
    aws:
      region: "us-east-2"
      assume_role:
        role_arn: "IAM Role ARN"
```

Similarly, it can be defined (or overridden) at the OU/tenant, account and region scopes in the corresponding
`_defaults.yaml` stack manifests.

If you want to override a provider configuration for a specific component, use the `component.terraform.<component>.providers`
section. For example, the following config can be used to override the `assume_role` parameter just for the `vpc` component:

**File:** `stacks/catalog/vpc/defaults.yaml`

```yaml
components:
  terraform:
    vpc:
      providers:
        aws:
          assume_role:
            role_arn: "IAM Role ARN for VPC"
```

You can include the `providers` sections in any Atmos stack manifest at any level of inheritance. Atmos will process,
deep-merge and override all the `providers` configurations for a component in the following order:

- Global scopes (`terraform.providers` sections for the Org, OUs, accounts and regions)
- Base component scope (`component.terraform.<base_component>.providers` section)
- Current component scope (`component.terraform.<component>.providers` section)

:::tip
Refer to [Atmos Component Inheritance](/howto/inheritance) for more information on all types of component inheritance
supported by Atmos
:::

When you define the `providers` sections, Atmos processes the inheritance chain for a component and generates a
file `providers_override.tf.json` in the component's folder with the final values for all the defined providers.

For example:

```shell
> atmos terraform plan vpc -s plat-ue2-prod --logs-level=Trace

Variables for the component 'vpc' in the stack 'plat-ue2-prod':
  environment: ue2
  max_subnet_count: 3
  name: common
  namespace: cp
  region: us-east-2
  stage: prod
  tenant: plat

Writing the variables to file:
components/terraform/vpc/plat-ue2-prod.terraform.tfvars.json

Writing the provider overrides to file:
components/terraform/vpc/providers_override.tf.json
```

The generated `providers_override.tf.json` file would look like this:

**File:** `providers_override.tf.json`

```json
{
    "provider": {
      "aws": {
        "assume_role": {
          "role_arn": "IAM Role ARN for VPC"
        }
      }
    }
}
```

Terraform then uses the values in the generated `providers_override.tf.json` to
[override](https://developer.hashicorp.com/terraform/language/files/override) the parameters for all the providers in the file.

## `alias`: Multiple Provider Configuration in Atmos Manifests

Atmos allows you to define multiple configurations for the same provider using a list of provider blocks and the
`alias` meta-argument.

The generated `providers_override.tf.json` file will have a list of provider configurations, and Terraform/OpenTofu
will use and override the providers as long as the aliased providers are defined in the Terraform component.

For example:

**File:** `stacks/catalog/vpc/defaults.yaml`

```yaml
components:
  terraform:
    vpc:
      providers:
        aws:
          - region: us-west-2
            assume_role:
              role_arn: "role-1"
          - region: us-west-2
            alias: "account-2"
            assume_role:
              role_arn: "role-2"
```

:::warning

The above example uses a list of configuration blocks for the `aws` provider.

Since it's a list, by default it doesn't work with deep-merging of stacks in the
[inheritance](/howto/inheritance) chain since lists are not deep-merged, they are replaced.

If you want to use the above configuration in the inheritance chain and allow appending or merging of lists, consider
configuring the `settings.list_merge_strategy` in the `atmos.yaml` CLI config file.

For more details, refer to [Atmos CLI Settings](/cli/configuration/settings).

:::

## Local Provider Development with Dev Overrides

When developing custom Terraform providers locally, you need a way to test them without publishing to a registry.
Terraform supports this through [development overrides](https://developer.hashicorp.com/terraform/cli/config/config-file#development-overrides-for-provider-developers),
which allows you to point Terraform to locally-built provider binaries.

:::info Important Distinction

This section covers **development overrides** for locally-built provider binaries, which is separate from the
**provider configuration** described in the sections above:

- **Provider Configuration** (`providers` section in Atmos stacks) → Controls provider behavior (credentials, regions, endpoints)
- **Development Overrides** (`.terraformrc` file) → Points to local provider binaries during development

:::

### Understanding Provider Configuration vs. Development Overrides

The `providers` section in Atmos stack manifests (covered above) configures **how providers behave** - things like
credentials, regions, and endpoints. This configuration is serialized to `providers_override.tf.json` and used by
Terraform to override provider settings.

Development overrides work at a different level: they tell Terraform **where to find the provider binary** itself.
This is configured in Terraform's CLI configuration file (`.terraformrc` or `terraform.rc`), not in your stack manifests.

### Setting Up Development Overrides with Atmos

To use locally-built providers with Atmos, follow these steps:

**1. Create a Terraform CLI configuration file with dev\_overrides in your component folder.**

Create a `.terraformrc` file in your **component directory** (e.g., `components/terraform/mycomponent/.terraformrc`):

**File:** `components/terraform/mycomponent/.terraformrc`

```
provider_installation {
  dev_overrides {
    "registry.terraform.io/myorg/myprovider" = "/absolute/path/to/provider/binary/directory"
  }

  # For all other providers, install them directly as normal.
  direct {}
}
```

Replace `myorg/myprovider` with your provider's registry address and `/absolute/path/to/provider/binary/directory`
with the **absolute path to the directory** containing your locally-built provider binary (not the binary itself).

:::warning Component-Specific Configuration

The `.terraformrc` file should be placed in each **component folder** that needs to use the local provider, not in
your infrastructure repository root. This is because Terraform's CLI configuration is loaded relative to where
Terraform runs, and Atmos executes Terraform from within the component directory.

**Do not commit** `.terraformrc` to version control - it contains developer-specific local paths. Add it to your
component's `.gitignore` or your global `.gitignore`.

:::

:::tip CLI Configuration Requirements

The `provider_installation` block with `dev_overrides` **must** be in a Terraform CLI configuration file
(`.terraformrc` or `terraform.rc`). It **cannot** be defined in `.tf` files like `providers.tf` because it's a
CLI-level setting, not infrastructure configuration.

:::

**2. Point Terraform to your CLI configuration.**

Set the `TF_CLI_CONFIG_FILE` environment variable in your component's `env` section to tell Terraform where to find
this configuration:

**File:** `stacks/catalog/mycomponent/defaults.yaml`

```yaml
components:
  terraform:
    mycomponent:
      env:
        # Points to .terraformrc in the component directory
        # Atmos runs Terraform from the component folder, so this resolves correctly
        TF_CLI_CONFIG_FILE: ".terraformrc"
```

:::tip Relative Paths Work

Since Atmos executes Terraform from within the component directory, you can use a relative path like `.terraformrc`.
Atmos will resolve it correctly to `components/terraform/mycomponent/.terraformrc`.

Alternatively, you can use an absolute path or `${PWD}/.terraformrc` if you prefer explicit paths.

:::

**3. Build your provider.**

Build your provider and place the binary in the directory you specified:

```shell
cd /path/to/your/provider
go build -o /path/to/provider/binary/terraform-provider-myprovider
```

**4. Run Atmos commands as usual.**

Now when you run Atmos commands, Terraform will use your locally-built provider:

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

:::tip Development Workflow

During active development, you can:

1. Make changes to your provider code
2. Rebuild the provider binary
3. Run `atmos terraform plan/apply` immediately without publishing a release
4. Iterate quickly on provider functionality

This eliminates the need to publish development versions to a registry during active development.

:::

### Using settings Section for Environment Variables

You can also use the `settings` section to manage environment variables across your stack hierarchy:

**File:** `stacks/orgs/acme/_defaults.yaml`

```yaml
terraform:
  settings:
    provider_dev_mode: true
    provider_dev_path: "/Users/developer/providers/bin"

components:
  terraform:
    mycomponent:
      env:
        TF_CLI_CONFIG_FILE: "${PWD}/.terraformrc"
```

Then reference these settings in your components as needed. However, note that the actual `.terraformrc` file
configuration cannot be templated through Atmos - it must exist as a file that Terraform can read directly.

:::warning Dev Overrides Warning

When dev\_overrides are active, Terraform will show a warning on every command:

```
Warning: Provider development overrides are in effect
```

This is expected behavior and confirms that your local provider is being used. Remove or comment out the
`dev_overrides` block in `.terraformrc` when you're ready to use the published provider version.

:::

### Example: Complete Setup

Here's a complete example for developing a custom provider:

**Directory Structure:**

```
infrastructure/
├── components/
│   └── terraform/
│       └── myapp/
│           ├── .terraformrc          # CLI config (not committed)
│           ├── .gitignore            # Ignore .terraformrc
│           ├── main.tf
│           ├── providers.tf
│           └── versions.tf
└── stacks/
    └── catalog/
        └── myapp/
            └── defaults.yaml
```

**File:** `components/terraform/myapp/.terraformrc`

```
provider_installation {
  dev_overrides {
    "registry.terraform.io/acme/cloud" = "/Users/developer/providers/bin"
  }
  direct {}
}
```

**File:** `components/terraform/myapp/.gitignore`

```
# Don't commit developer-specific CLI config
.terraformrc
```

**File:** `stacks/catalog/myapp/defaults.yaml`

```yaml
components:
  terraform:
    myapp:
      # Configure the provider's behavior (credentials, endpoints, etc.)
      providers:
        acme:
          endpoint: "https://api.acme.com"
          api_token: "{{ .settings.acme_api_token }}"

      # Point to the CLI config in the component directory
      env:
        TF_CLI_CONFIG_FILE: ".terraformrc"

      # Regular component configuration
      vars:
        name: "my-application"
```

With this setup:

- `.terraformrc` lives in the component folder where Terraform executes
- Terraform finds your local provider binary via `.terraformrc`
- Atmos configures the provider's behavior via the `providers` section
- Your component works seamlessly with the local provider during development
- The file is not committed, so each developer can have their own local paths

## References

- [Terraform Providers](https://developer.hashicorp.com/terraform/language/providers)
- [Terraform Override Files](https://developer.hashicorp.com/terraform/language/files/override)
- [alias: Multiple Provider Configurations](https://developer.hashicorp.com/terraform/language/providers/configuration#alias-multiple-provider-configurations)
- [Terraform Development Overrides](https://developer.hashicorp.com/terraform/cli/config/config-file#development-overrides-for-provider-developers) - Official guide for provider development
