Multi-region Terraform — deploy to multiple regions with shared code.
Module-based approach:
1# modules/region/main.tf2resource "aws_vpc" "main" {3 cidr_block = var.vpc_cidr4 tags = {5 Name = "${var.region}-vpc"6 Region = var.region7 }8}910resource "aws_instance" "web" {11 ami = var.ami_id12 instance_type = var.instance_type13 subnet_id = aws_subnet.main.id14}1516variable "region" { type = string }17variable "vpc_cidr" { type = string }18variable "ami_id" { type = string }19variable "instance_type" { type = string }2021output "vpc_id" { value = aws_vpc.main.id }22output "instance_ip" { value = aws_instance.web.public_ip }
Root module (for_each per region):
1# main.tf2variable "regions" {3 default = {4 us-east-1 = {5 vpc_cidr = "10.0.0.0/16"6 instance_type = "t3.micro"7 }8 eu-west-1 = {9 vpc_cidr = "10.1.0.0/16"10 instance_type = "t3.small"11 }12 }13}1415module "region" {16 source = "./modules/region"17 for_each = var.regions1819 region = each.key20 vpc_cidr = each.value.vpc_cidr21 instance_type = each.value.instance_type22 ami_id = data.aws_ami.amazon_linux[each.key].id23}2425provider "aws" {26 alias = "us_east_1"27 region = "us-east-1"28}2930data "aws_ami" "amazon_linux" {31 for_each = var.regions32 provider = aws.us_east_133 most_recent = true34 owners = ["amazon"]35 filter {36 name = "name"37 values = ["amzn2-ami-hvm-*-x86_64-gp2"]38 }39}
Global resources (Route53):
1resource "aws_route53_record" "failover" {2 for_each = module.region3 zone_id = aws_route53_zone.main.zone_id4 name = "myapp.${each.key}.example.com"5 type = "A"6 ttl = 607 records = [each.value.instance_ip]8}
Terragrunt approach: Separate folders for each region with shared modules.