# Generate Terraform Files

The `generate` section creates auxiliary configuration files for Terraform components based on your stack configuration. Define file templates once in your stacks and Atmos generates the appropriate files in each component directory.

> ⚠️ Experimental

## How It Works

When you run `atmos terraform generate files` (or any terraform command with `auto_generate_files` enabled), Atmos:

1. Reads the `generate` section from the component's stack configuration
2. Processes each file definition using extension-aware serialization or Go templates
3. Writes the generated files to the component directory
4. Makes template context variables available for dynamic content

This separation means you can generate environment-specific configuration files without hardcoding values in your Terraform modules.

## Concepts

The `generate` block is declarative code generation for Terraform component directories. You describe the files in stack configuration, and Atmos writes those files next to the Terraform root module before Terraform runs.

Use `generate` when a file belongs with a Terraform component at runtime, but the file's content should come from Atmos stack configuration. This keeps the reusable component HCL focused on infrastructure behavior while stack-specific values remain in stack manifests.

The `generate` section can be defined in several places:

- `components.terraform.<component>.generate` for one component instance
- an inherited component's `generate` section, usually through `metadata.inherits`
- `terraform.generate` for all Terraform components in the current stack scope
- `terraform.overrides.generate` for file-scoped Terraform component overrides with the highest priority

Files are written relative to the resolved Terraform component directory. If a component uses `metadata.component`, Atmos writes generated files into that resolved component folder, not necessarily a folder named after the Atmos component instance.

:::tip Generated Files
Add generated files to your `.gitignore` since they are created automatically by Atmos:

```gitignore
# Atmos generated files
locals.tf
*.generated.tf
*_override.tf
*_override.tf.json
```

:::

## Use Cases

- **Dynamic Locals and Context:** Generate `locals.tf`, `context.tf`, or `context.auto.tfvars.json` files with environment-specific values from stack configuration.
- **Provider-Adjacent Configuration:** Create extra provider aliases, required provider settings, or supporting HCL that depends on the stack context.
- **Documentation:** Generate README files with component metadata, workspace names, or stack-specific usage notes.
- **Terraform Overrides:** Generate Terraform override files to patch a vendored component without editing upstream HCL.
- **Custom Configuration:** Create any auxiliary files your Terraform modules need.

:::important Terraform Override Filenames
Terraform only treats a file as an override file when it is named `override.tf`, `override.tf.json`, `*_override.tf`, or `*_override.tf.json`.

Use those names when generating Terraform overrides. For normal generated files, use ordinary filenames like `locals.tf`, `context.tf`, or `context.auto.tfvars.json`.
:::

## Configuration

The `generate` section is defined at the component level in stack configuration:

### Stack Configuration

```yaml title="stacks/orgs/acme/plat/prod/us-east-1.yaml"
components:
  terraform:
    vpc:
      vars:
        environment: prod
        vpc_cidr: "10.0.0.0/16"
      generate:
        # Map values are serialized based on file extension
        "locals.tf":
          locals:
            environment: "{{ .vars.environment }}"
            vpc_cidr: "{{ .vars.vpc_cidr }}"

        # String values are treated as Go templates
        "README.md": |
          # VPC Component
          Environment: {{ .vars.environment }}
          Stack: {{ .atmos_stack }}
```

### Generated locals.tf

```hcl title="components/terraform/vpc/locals.tf"
locals {
  environment = "prod"
  vpc_cidr    = "10.0.0.0/16"
}
```

### Generated README.md

```markdown title="components/terraform/vpc/README.md"
# VPC Component
Environment: prod
Stack: plat-ue1-prod
```

## Extension-Aware Serialization

When the value is a map, Atmos serializes it based on the file extension:

| Extension | Format | Description |
|-----------|--------|-------------|
| `.tf`, `.hcl` | HCL | Valid Terraform/HCL syntax |
| `.json` | JSON | 2-space indented JSON |
| `.yaml`, `.yml` | YAML | 2-space indented YAML |
| Other | JSON | Defaults to JSON format |

### HCL Generation Example

### Stack Configuration

```yaml
components:
  terraform:
    vpc:
      generate:
        "locals.tf":
          locals:
            environment: "{{ .vars.environment }}"
            tags:
              ManagedBy: Atmos
              Component: "{{ .component }}"
```

### Generated File

```hcl title="components/terraform/vpc/locals.tf"
locals {
  environment = "prod"
  tags = {
    Component = "vpc"
    ManagedBy = "Atmos"
  }
}
```

### JSON Generation Example

### Stack Configuration

```yaml
components:
  terraform:
    vpc:
      generate:
        "config.json":
          settings:
            environment: "{{ .vars.environment }}"
            region: "{{ .vars.region }}"
```

### Generated File

```json title="components/terraform/vpc/config.json"
{
  "settings": {
    "environment": "prod",
    "region": "us-east-1"
  }
}
```

## Template Context

String values and map string values are processed as Go templates with access to the full component context:

### Available Variables

- **`{{ .vars }}`**
  Component variables from the 
  `vars`
   section.
- **`{{ .settings }}`**
  Component settings from the 
  `settings`
   section.
- **`{{ .env }}`**
  Component environment variables from the 
  `env`
   section.
- **`{{ .backend }}`**
  Backend configuration.
- **`{{ .backend_type }}`**
  Backend type (e.g., 
  `s3`
  , 
  `azurerm`
  ).
- **`{{ .providers }}`**
  Provider configurations.
- **`{{ .metadata }}`**
  Component metadata.
- **`{{ .namespace }}`**
  Namespace context variable.
- **`{{ .tenant }}`**
  Tenant context variable.
- **`{{ .environment }}`**
  Environment context variable.
- **`{{ .stage }}`**
  Stage context variable.
- **`{{ .region }}`**
  Region context variable (if defined in vars).
- **`{{ .atmos_component }}`**
  Atmos component name.
- **`{{ .atmos_stack }}`**
  Atmos stack name.
- **`{{ .component }}`**
  Final component name (after inheritance resolution).
- **`{{ .workspace }}`**
  Terraform workspace name.

### Template Example

**File:** `stacks/orgs/acme/plat/prod/us-east-1.yaml`

```yaml
components:
  terraform:
    vpc:
      vars:
        environment: prod
        vpc_cidr: "10.0.0.0/16"
        availability_zones:
          - us-east-1a
          - us-east-1b
      generate:
        "context.tf": |
          # Generated by Atmos - DO NOT EDIT
          locals {
            atmos_stack     = "{{ .atmos_stack }}"
            atmos_component = "{{ .atmos_component }}"
            environment     = "{{ .vars.environment }}"
          }
```

## Auto-Generation

Enable automatic file generation during terraform commands by setting `auto_generate_files` in your `atmos.yaml`:

**File:** `atmos.yaml`

```yaml
components:
  terraform:
    auto_generate_files: true
```

When enabled, Atmos generates files from the `generate` section before executing any terraform command (`plan`, `apply`, etc.).

## Examples

### Generate Locals from Variables

Create a `locals.tf` that mirrors select variables:

### Stack Configuration

```yaml
components:
  terraform:
    eks:
      vars:
        cluster_name: acme-prod
        cluster_version: "1.28"
        node_groups:
          default:
            instance_type: m5.large
            desired_size: 3
      generate:
        "locals.tf":
          locals:
            cluster_name: "{{ .vars.cluster_name }}"
            cluster_version: "{{ .vars.cluster_version }}"
            environment: "{{ .vars.environment }}"
```

### Generated File

```hcl title="components/terraform/eks/locals.tf"
locals {
  cluster_name    = "acme-prod"
  cluster_version = "1.28"
  environment     = "prod"
}
```

### Generate Multiple Files

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

```yaml
components:
  terraform:
    vpc:
      generate:
        # HCL locals file
        "locals.tf":
          locals:
            environment: "{{ .vars.environment }}"
            stage: "{{ .stage }}"

        # JSON configuration
        "atmos-metadata.json":
          stack: "{{ .atmos_stack }}"
          component: "{{ .atmos_component }}"
          workspace: "{{ .workspace }}"

        # Markdown documentation
        "README.md": |
          # {{ .atmos_component }}

          This component is deployed to the `{{ .atmos_stack }}` stack.

          ## Variables

          - Environment: {{ .vars.environment }}
          - Stage: {{ .stage }}
```

### Conditional Content with Templates

Use Go template conditionals for dynamic content:

```yaml
components:
  terraform:
    vpc:
      vars:
        enable_nat_gateway: true
        single_nat_gateway: false
      generate:
        "nat-config.tf": |
          locals {
            {{ if .vars.enable_nat_gateway }}
            nat_gateway_enabled = true
            {{ if .vars.single_nat_gateway }}
            nat_gateway_count = 1
            {{ else }}
            nat_gateway_count = length(var.availability_zones)
            {{ end }}
            {{ else }}
            nat_gateway_enabled = false
            nat_gateway_count   = 0
            {{ end }}
          }
```

### Component Inheritance with Generate

The `generate` section is inherited and merged like other component sections:

### Catalog Defaults

```yaml title="stacks/catalog/vpc/_defaults.yaml"
components:
  terraform:
    vpc/defaults:
      metadata:
        type: abstract
      generate:
        "locals.tf":
          locals:
            managed_by: Atmos
```

### Stack Override

```yaml title="stacks/orgs/acme/plat/prod/us-east-1.yaml"
import:
  - catalog/vpc/_defaults

components:
  terraform:
    vpc:
      metadata:
        inherits:
          - vpc/defaults
      generate:
        # Merged with inherited generate section
        "locals.tf":
          locals:
            managed_by: Atmos
            environment: "{{ .vars.environment }}"
```

### Terraform Overrides for Vendored Components

Use `generate` to create Terraform override files when you need to patch a vendored component without changing the vendored source. This is useful for small, deliberate changes such as overriding an argument, adding a lifecycle rule, or adding a provider alias while keeping upstream code intact.

### Stack Configuration

```yaml title="stacks/catalog/vpc/defaults.yaml"
components:
  terraform:
    vpc:
      metadata:
        component: cloudposse/vpc
      vars:
        protect_default_security_group: true
      generate:
        "default_security_group_override.tf": |
          # Generated by Atmos - DO NOT EDIT
          resource "aws_default_security_group" "default" {
            lifecycle {
              prevent_destroy = {{ .vars.protect_default_security_group }}
            }
          }
```

### Generated Override

```hcl title="components/terraform/cloudposse/vpc/default_security_group_override.tf"
# Generated by Atmos - DO NOT EDIT
resource "aws_default_security_group" "default" {
  lifecycle {
    prevent_destroy = true
  }
}
```

Terraform loads this file as an override because the filename ends in `_override.tf`. Use this pattern carefully: Terraform overrides depend on resource names and block structure inside the upstream component, so they can break when the vendored component changes.

### File-Scoped Generate Overrides

Use `terraform.overrides.generate` when the generated file should apply only to the Terraform components visible from the current manifest and its imports. Like other [overrides](/stacks/overrides), this is file-scoped and has the highest merge priority.

```yaml title="stacks/teams/network.yaml"
import:
  - catalog/vpc/defaults
  - catalog/transit-gateway/defaults

terraform:
  overrides:
    generate:
      "team-context.generated.tf":
        locals:
          team: Network
          managed_by: Atmos
```

## Cleaning Generated Files

Remove generated files with the `--clean` flag:

```shell
# Clean generated files for a single component
atmos terraform generate files vpc -s prod-ue2 --clean

# Clean generated files for all components
atmos terraform generate files --all --clean
```

## Best Practices

1. **Use for Environment-Specific Values:** Generate files for values that vary by environment rather than hardcoding in modules.

2. **Add to .gitignore:** Generated files should not be committed to version control.

3. **Document Generated Files:** Add comments indicating the file is generated and should not be edited manually.

4. **Use Consistent Naming:** Establish naming conventions for generated files (e.g., `*.generated.tf`).

5. **Leverage Inheritance:** Define common generate patterns in catalog defaults and inherit them.

6. **Preview Before Applying:** Use `--dry-run` to preview what will be generated.

## Related

- [atmos terraform generate files](/cli/commands/terraform/generate/files) - CLI command reference
- [Terraform Components](/stacks/components/terraform) - Component configuration overview
- [Terraform Backend](/stacks/backend) - Backend file generation
- [Terraform Providers](/stacks/providers) - Provider file generation
- [Variables (vars)](/stacks/vars) - Defining component variables
