Skip to main content

Generate Terraform Backend

The backend section generates Terraform backend configuration files (backend.tf.json) for your components. Define backend settings once in your stacks and Atmos generates the appropriate files for each environment.

How It Works​

When you run any atmos terraform command, Atmos:

  1. Reads your backend and backend_type configuration from the stack
  2. Deep-merges settings from all inherited stack manifests
  3. Generates a backend.tf.json file in the component directory
  4. Terraform uses this file to configure state storage

This separation means your Terraform modules stay cleanβ€”no hardcoded backend configuration in your source code.

Generated Files

Add backend.tf.json to your .gitignore since these files are generated automatically by Atmos and should not be committed to version control:

# Atmos generated files
backend.tf.json

Some automation systems may require the generated file to be committedβ€”in those cases, committing backend.tf.json is acceptable.

Use Cases​

  • State Management: Configure S3, Azure Blob, GCS, or other backends for remote state storage.
  • Environment Isolation: Use different state storage per environment or account.
  • State Locking: Configure native locking (use_lockfile) or DynamoDB for legacy setups.
  • Remote State Access: Configure remote_state_backend for cross-component state references.

Configuration Scopes​

Backend settings can be defined at multiple levels, with more specific scopes overriding broader ones:

ScopeExample FileEffect
Organizationstacks/orgs/acme/_defaults.yamlAll components inherit
Account/Stagestacks/orgs/acme/plat/prod/_defaults.yamlOverride for prod
Component-typeUnder terraform: in any stackAll Terraform components
ComponentUnder components.terraform.<name>:Single component

Component-Type Level​

Backend settings defined under terraform apply to all Terraform components:

stacks/orgs/acme/_defaults.yaml
terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-root-tfstate
region: us-east-1
encrypt: true
use_lockfile: true

Component Level​

Backend settings within a component override the defaults:

stacks/orgs/acme/plat/prod/us-east-1.yaml
components:
terraform:
special-component:
backend_type: s3
backend:
s3:
bucket: acme-ue1-prod-special-tfstate
key: "special/terraform.tfstate"

Backend Types​

Atmos supports all Terraform backend types. Configure using backend_type and the corresponding configuration under backend.

S3 Backend​

The most common backend for AWS environments. We recommend using use_lockfile: true for native S3 state locking (Terraform 1.10+, OpenTofu 1.8+) instead of DynamoDB:

terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-root-tfstate
region: us-east-1
key: "{{ .environment }}/{{ .stage }}/{{ .component }}/terraform.tfstate"
encrypt: true
use_lockfile: true # Native S3 locking (Terraform 1.10+)

S3 Backend with Assume Role​

For cross-account access, configure the backend to assume a role:

terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-root-tfstate
region: us-east-1
key: "{{ .environment }}/{{ .stage }}/{{ .component }}/terraform.tfstate"
encrypt: true
use_lockfile: true
assume_role:
role_arn: "arn:aws:iam::{{ .vars.state_account_id }}:role/TerraformStateAccess"
session_name: "atmos-{{ .component }}"

S3 Backend with DynamoDB Locking (Legacy)​

For Terraform versions before 1.10, use DynamoDB for state locking:

terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-root-tfstate
region: us-east-1
key: "{{ .environment }}/{{ .stage }}/{{ .component }}/terraform.tfstate"
dynamodb_table: acme-ue1-root-tfstate-lock
encrypt: true

Azure Blob Backend​

For Azure environments:

terraform:
backend_type: azurerm
backend:
azurerm:
resource_group_name: terraform-state-rg
storage_account_name: tfstateaccount
container_name: tfstate
key: "{{ .environment }}/{{ .stage }}/{{ .component }}/terraform.tfstate"

GCS Backend​

For Google Cloud environments:

terraform:
backend_type: gcs
backend:
gcs:
bucket: acme-terraform-state
prefix: "{{ .environment }}/{{ .stage }}/{{ .component }}"

Terraform Cloud / Enterprise​

For Terraform Cloud or Enterprise:

terraform:
backend_type: remote
backend:
remote:
hostname: app.terraform.io
organization: acme
workspaces:
name: "{{ .namespace }}-{{ .environment }}-{{ .stage }}-{{ .component }}"

Or using the newer cloud backend:

terraform:
backend_type: cloud
backend:
cloud:
organization: acme
workspaces:
name: "{{ .namespace }}-{{ .environment }}-{{ .stage }}-{{ .component }}"

Local Backend​

For development or single-user scenarios:

terraform:
backend_type: local
backend:
local:
path: "{{ .component }}/terraform.tfstate"

Remote State Backend​

The remote_state_backend configuration is separate from backend and controls how other components can read this component's state:

terraform:
# Where this component stores its state
backend_type: s3
backend:
s3:
bucket: acme-ue1-root-tfstate
region: us-east-1

# How other components read this component's state
remote_state_backend_type: s3
remote_state_backend:
s3:
bucket: acme-ue1-root-tfstate
region: us-east-1

This separation allows for scenarios like:

  • Using Terraform Cloud for operations but S3 for remote state access
  • Different credentials for writing vs. reading state
  • Custom remote state configurations

Backend Provisioning​

Atmos can automatically provision S3 backend infrastructure before running Terraform commands, solving the bootstrap problem of "how do I create state storage before I can use Terraform?"

Enable Automatic Provisioning​

terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-dev-tfstate
region: us-east-1
use_lockfile: true

provision:
backend:
enabled: true # Automatically create backend if it doesn't exist

When provision.backend.enabled is true, Atmos will:

  1. Check if the backend exists before running Terraform
  2. Create it with secure defaults (versioning, encryption, public access blocked)
  3. Proceed with normal Terraform operations

See Backend Provisioning for complete documentation.

Examples​

Environment-Specific State Buckets​

stacks/orgs/acme/plat/dev/_defaults.yaml

terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-dev-tfstate
region: us-east-1
encrypt: true
use_lockfile: true

stacks/orgs/acme/plat/prod/_defaults.yaml

terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-prod-tfstate
region: us-east-1
encrypt: true
use_lockfile: true

Dynamic State Keys with Templates​

stacks/orgs/acme/_defaults.yaml

terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-root-tfstate
region: "{{ .vars.region }}"
key: "{{ .environment }}/{{ .stage }}/{{ .component }}/terraform.tfstate"
encrypt: true
use_lockfile: true

Component-Specific Backend Override​

stacks/orgs/acme/plat/prod/us-east-1.yaml

import:
- orgs/acme/_defaults

components:
terraform:
# Uses default backend
vpc:
vars:
vpc_cidr: "10.0.0.0/16"

# Uses custom backend for sensitive data
secrets-manager:
backend_type: s3
backend:
s3:
bucket: acme-ue1-prod-secrets-tfstate
region: us-east-1
key: "secrets/terraform.tfstate"
encrypt: true
use_lockfile: true
kms_key_id: alias/terraform-state-key
vars:
# ...

Multi-Cloud Configuration​

stacks/orgs/acme/aws/_defaults.yaml

terraform:
backend_type: s3
backend:
s3:
bucket: acme-ue1-root-tfstate
region: us-east-1
use_lockfile: true

stacks/orgs/acme/azure/_defaults.yaml

terraform:
backend_type: azurerm
backend:
azurerm:
resource_group_name: terraform-state-rg
storage_account_name: acmetfstate
container_name: tfstate

Workspace Configuration​

For backends that support workspaces, you can configure workspace patterns:

terraform:
backend_type: remote
backend:
remote:
organization: acme
workspaces:
prefix: "acme-"

components:
terraform:
vpc:
terraform_workspace: "{{ .environment }}-{{ .stage }}-vpc"

See Terraform Workspaces for detailed workspace configuration.

Best Practices​

  1. Use Remote State: Always use a remote backend for team environments to enable collaboration and state locking.

  2. Enable Encryption: Always enable encryption for backends that support it (S3, Azure Blob, GCS).

  3. Configure State Locking: Use use_lockfile: true for S3 (Terraform 1.10+), blob leases for Azure, or built-in locking for other backends.

  4. Organize State Keys: Use a consistent key structure that includes environment, stage, and component information.

  5. Separate Sensitive State: Consider using separate state buckets or additional encryption for components managing secrets.

  6. Use Templates: Leverage Go templates for dynamic backend configuration based on context variables.