Terraform Stacks Explained: What They Are and When to Use Them

HashiCorp introduced Terraform Stacks to solve a problem that's plagued infrastructure teams for years: managing related infrastructure components that need to be deployed together, across multiple environments, with proper dependency ordering.

If you've ever struggled with Terragrunt dependency chains, custom CI/CD orchestration scripts, or copy-pasting modules across environment directories - Stacks is HashiCorp's answer to that pain.
______
The Problem Stacks Solves
Consider a typical application deployment:
Networking ──▶ Database ──▶ Application
(VPC) (RDS) (EKS)
These components have dependencies. You can't create the database until networking exists. You can't deploy the application until the database is ready. Now multiply this across dev, staging, and production environments.
Traditional approaches to this problem all have drawbacks:
- Multiple terraform apply commands - Manual ordering, error-prone, doesn't scale
- Terragrunt - Works but adds another tool to learn and maintain
- CI/CD orchestration - Custom pipelines with dependency logic that nobody wants to touch
- Monolithic configs - Everything in one state file doesn't scale and becomes unwieldy
- Stacks provides a native Terraform solution that handles all of this.
______
What is a Terraform Stack?
A Stack is a collection of Terraform components that are deployed together with defined dependencies. It introduces three new concepts:
- Components - Individual Terraform configurations (your existing modules work here)
- Deployments - Environment-specific instances of your stack (dev, staging, prod)
- Orchestration - Automatic dependency resolution and parallel execution

Stack Structure
1my-stack/
2├── tfdeploy.hcl # Deployment configuration
3├── tfstack.hcl # Stack definition
4├── components/
5│ ├── networking/
6│ │ ├── main.tf
7│ │ ├── variables.tf
8│ │ └── outputs.tf
9│ ├── database/
10│ │ ├── main.tf
11│ │ ├── variables.tf
12│ │ └── outputs.tf
13│ └── application/
14│ ├── main.tf
15│ ├── variables.tf
16│ └── outputs.tf
_______
Defining a Stack
Stack Configuration (tfstack.hcl)
1required_providers {
2 aws = {
3 source = "hashicorp/aws"
4 version = "~> 5.0"
5 }
6}
7
8variable "environment" {
9 type = string
10}
11
12variable "region" {
13 type = string
14 default = "ap-south-1"
15}
16
17variable "vpc_cidr" {
18 type = string
19}
20
21provider "aws" "main" {
22 config {
23 region = var.region
24 }
25}
26
27# Networking Component
28component "networking" {
29 source = "./components/networking"
30
31 providers = {
32 aws = provider.aws.main
33 }
34
35 inputs = {
36 environment = var.environment
37 vpc_cidr = var.vpc_cidr
38 }
39}
40
41# Database Component - depends on networking
42component "database" {
43 source = "./components/database"
44
45 providers = {
46 aws = provider.aws.main
47 }
48
49 inputs = {
50 environment = var.environment
51 vpc_id = component.networking.vpc_id
52 private_subnet_ids = component.networking.private_subnet_ids
53 }
54}
55
56# Application Component - depends on both
57component "application" {
58 source = "./components/application"
59
60 providers = {
61 aws = provider.aws.main
62 }
63
64 inputs = {
65 environment = var.environment
66 vpc_id = component.networking.vpc_id
67 private_subnet_ids = component.networking.private_subnet_ids
68 database_endpoint = component.database.endpoint
69 database_secret = component.database.secret_arn
70 }
71}Notice how dependencies are implicit. When database references component.networking.vpc_id, Stacks knows to create networking first. No explicit depends_on blocks needed.
Deployment Configuration (tfdeploy.hcl)
1identity_token "aws" {
2 audience = ["terraform-stacks"]
3}
4
5deployment "dev" {
6 inputs = {
7 environment = "dev"
8 region = "ap-south-1"
9 vpc_cidr = "10.1.0.0/16"
10 }
11}
12
13deployment "staging" {
14 inputs = {
15 environment = "staging"
16 region = "ap-south-1"
17 vpc_cidr = "10.2.0.0/16"
18 }
19}
20
21deployment "prod" {
22 inputs = {
23 environment = "prod"
24 region = "ap-south-1"
25 vpc_cidr = "10.0.0.0/16"
26 }
27}One stack definition, multiple deployments. Each deployment gets its own state and can have environment-specific configurations. This is the DRY principle applied to multi-environment infrastructure.
______
Component Deep Dive
Components are standard Terraform configurations. Here's what the networking component might look like:
1# components/networking/main.tf
2variable "environment" {
3 type = string
4}
5
6variable "vpc_cidr" {
7 type = string
8}
9
10module "vpc" {
11 source = "terraform-aws-modules/vpc/aws"
12 version = "~> 5.0"
13
14 name = "main-${var.environment}"
15 cidr = var.vpc_cidr
16
17 azs = ["ap-south-1a", "ap-south-1b", "ap-south-1c"]
18 private_subnets = [cidrsubnet(var.vpc_cidr, 4, 0), cidrsubnet(var.vpc_cidr, 4, 1), cidrsubnet(var.vpc_cidr, 4, 2)]
19 public_subnets = [cidrsubnet(var.vpc_cidr, 4, 3), cidrsubnet(var.vpc_cidr, 4, 4), cidrsubnet(var.vpc_cidr, 4, 5)]
20
21 enable_nat_gateway = true
22 single_nat_gateway = var.environment != "prod"
23
24 tags = {
25 Environment = var.environment
26 }
27}
28
29output "vpc_id" {
30 value = module.vpc.vpc_id
31}
32
33output "private_subnet_ids" {
34 value = module.vpc.private_subnets
35}
36
37output "public_subnet_ids" {
38 value = module.vpc.public_subnets
39}The key difference from regular Terraform: outputs are automatically available to other components via component.<name>.<output>.
_______
How Stacks Executes
When you run a stack, Terraform:
- Analyzes dependencies - Builds a graph of component relationships
- Plans in parallel - Components without dependencies are planned simultaneously
- Applies in order - Respects dependency chain, parallelizes where possible
- Manages state - Each component gets isolated state within the deployment
1$ tfstacks plan dev
2
3Planning deployment "dev"...
4
5Component "networking": Planning...
6Component "networking": Plan complete. 12 to add.
7
8Component "database": Planning... (waiting for networking)
9Component "database": Plan complete. 8 to add.
10
11Component "application": Planning... (waiting for database)
12Component "application": Plan complete. 15 to add.
13
14Total: 35 resources to add across 3 components.
15______
Stacks vs Alternatives
Versus Terragrunt:
- Stacks has native dependency management; Terragrunt uses
dependencyblocks - Stacks has built-in deployments; Terragrunt uses directory structure
- Stacks is newer with HCP integration; Terragrunt has years of community patterns
Versus Workspaces:
- Stacks handles multi-component applications; workspaces handle single-component variations
- Stacks has automatic parallelization; workspaces require manual orchestration
- Stacks isolates state per component; workspaces share state
When Stacks is a good fit:
- Multi-component applications with clear dependencies
- Teams deploying the same architecture across multiple environments
- Organizations already using HCP Terraform
- New projects without existing Terragrunt investment
When Stacks isn't ideal:
- Simple, single-component infrastructure
- Teams heavily invested in Terragrunt workflows
- Scenarios requiring fine-grained control over individual components
______
Getting Started
1# HCP Terraform account required
2# Initialize a stack
3tfstacks init
4
5# Plan a deployment
6tfstacks plan <deployment-name>
7
8# Apply
9tfstacks apply <deployment-name>______
Wrapping Up
Terraform Stacks represents HashiCorp's vision for managing complex, multi-component infrastructure natively. It addresses real pain points - dependency ordering, environment management, and state isolation - without requiring external tools.
If you're starting fresh or evaluating your IaC orchestration strategy, Stacks deserves a serious look. For existing Terragrunt users, the migration path will depend on your specific workflows and willingness to adopt HCP Terraform.
The infrastructure orchestration space is evolving rapidly. Stacks is HashiCorp's bet on where it's heading. Whether that bet pays off depends on how quickly they expand availability beyond HCP and how the community builds around it.
For now, it's worth understanding what Stacks offers - even if you're not ready to adopt it today.
