Terraform stacks

Terraform stacks

A stack deploys the same infrastructure multiple times — across environments, regions, or accounts — from a single configuration. Where a traditional root module describes one deployment, a stack separates what to deploy (components) from where and how many times to deploy it (deployments). Stacks are orchestrated by HCP Terraform.

  flowchart LR
    subgraph stack["Stack"]
        comp["Components<br/>(what to deploy)"]
    end
    comp --> dev["Deployment: dev"]
    comp --> staging["Deployment: staging"]
    comp --> prod["Deployment: prod"]

A stack consists of two file types at the repository root:

  • *.tfcomponent.hcl — declares the components (modules) that make up the stack.
  • *.tfdeploy.hcl — declares the deployments, each with its own input values and state.

A component block sources a module and wires up its inputs, replacing the traditional root module:

components.tfcomponent.hcl
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
variable "environment" {
  type = string
}

component "network" {
  source = "./modules/network"

  inputs = {
    name = "${var.environment}-network"
  }
}

component "cluster" {
  source = "./modules/cluster"

  inputs = {
    environment = var.environment
    network_id  = component.network.id
  }
}

Components reference each other’s outputs with component.<NAME>.<output>, and Terraform works out the dependency order.

Each deployment block creates one full copy of all components, with its own isolated state:

deployments.tfdeploy.hcl
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
deployment "development" {
  inputs = {
    environment = "development"
  }
}

deployment "production" {
  inputs = {
    environment = "production"
  }
}

Adding a new environment or region is now a matter of adding one deployment block — no copy-pasting of root modules, no drift between environments.

Stacks require HCP Terraform, which plans and applies each deployment and orchestrates the order between them. Without stacks, the common alternative is one root module (or workspace) per environment.

Best practices

  • Use stacks when you deploy the same infrastructure more than once — multiple environments, regions, or customer instances; a single deployment does not need a stack.
  • Keep components thin: put the real logic in reusable modules and let component blocks only wire them together.
  • Let differences between deployments live in deployment inputs only, so environments cannot drift structurally.
  • Use OIDC (identity_token) for provider credentials in deployments instead of static secrets.