Architecting Terraform for Multi-Cloud: The Separate Runs Pattern

Intro: Why Separate Terraform Runs Matter

Writing one script to rule all clouds might sound like a DevOps dream—but in reality, maintaining a single Terraform config with logic to switch between AWS, Azure, and GCP can create more problems than it solves. In this post, I introduce the Separate Runs Pattern for structuring Terraform code across multiple clouds.

What is the Separate Runs Pattern?

We avoid multi-provider coupling by giving each cloud its own isolated Terraform root configuration:


terraform-multi-cloud/
├── aws/
├── azure/
├── gcp/
└── modules/
                            

Each directory contains its own state, variables, and provider setup, but calls shared modules to reduce code duplication.

Benefits of This Architecture

  • Isolated State: Fewer chances for accidental cross-cloud destruction.
  • Cleaner Pipelines: Each cloud deploys independently.
  • Scoped Credentials: Least-privilege access per environment.
  • Developer Autonomy: Teams own their cloud configurations without collisions.

Example: The AWS Root Config


provider "aws" {
  region = var.region
}

module "compute" {
  source        = "../modules/compute"
  name          = "aws-instance"
  region        = var.region
  instance_type = var.instance_type
  ami           = var.ami
}
                            

Using the Pattern

To deploy, just navigate to the cloud you want and run Terraform:


cd aws
terraform init
terraform apply
                            

Later:


cd ../gcp
terraform init
terraform apply
                            

Conclusion

If you're scaling Terraform across clouds, the Separate Runs Pattern keeps things maintainable, secure, and flexible. Combine isolation with shared modules and you'll build multi-cloud systems that are easier to test, extend, and trust.