Terraform Provider Aliases
A company with offices in two cities keeps a separate phone line in each one. A call to the New York office goes through the New York line, and a call to London goes through the London line. Terraform providers behave like those phone lines. One provider block connects to one region or one account. A project that spans two regions or two accounts needs a second line. Provider aliases supply it.
The Problem: One Provider, One Region
A plain provider block sets a single region.
provider "aws" {
region = "us-east-1"
}Every resource now lands in us-east-1. A backup bucket in us-west-2 has no way to reach another region through this block.
Creating an Alias
Add a second provider block with an alias argument. The block without an alias becomes the default. The block with an alias stays available on request.
provider "aws" {
region = "us-east-1"
}
provider "aws" {
alias = "west"
region = "us-west-2"
}Diagram: Two Lines, Two Regions
+-------------------+
| Terraform config |
+---------+---------+
|
+----------------+----------------+
| |
provider "aws" provider "aws" alias "west"
region us-east-1 region us-west-2
| |
v v
+-----------------+ +-----------------+
| Primary bucket | | Backup bucket |
+-----------------+ +-----------------+Choosing a Provider for a Resource
A resource without a provider argument uses the default provider. Add the argument to pick the alias. The reference format is PROVIDER.ALIAS.
resource "aws_s3_bucket" "primary" {
bucket = "shop-primary-2026"
}
resource "aws_s3_bucket" "backup" {
provider = aws.west
bucket = "shop-backup-2026"
}Terraform creates the first bucket in us-east-1 and the second in us-west-2 during the same run.
Data Sources Accept Aliases Too
data "aws_availability_zones" "west" {
provider = aws.west
state = "available"
}Passing Aliases to Modules
A module uses the default provider unless the caller says otherwise. The providers argument passes a specific provider into the module.
module "backup_network" {
source = "./modules/network"
providers = {
aws = aws.west
}
}Inside the module, the code refers to a plain aws provider. The caller decides which real connection hides behind that name.
Modules That Need Two Providers
A module that works across two regions declares the extra provider name in its own required_providers block.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
configuration_aliases = [aws.replica]
}
}
}The caller then passes both connections.
module "database" {
source = "./modules/database"
providers = {
aws = aws
aws.replica = aws.west
}
}Common Uses for Aliases
| Use Case | Example |
|---|---|
| Multi-region setup | Primary app in one region and backups in another |
| Multiple accounts | A shared logging account beside a workload account |
| Global services | A certificate that must live in a specific region |
| Disaster recovery | A standby copy in a distant region |
Multiple Accounts With Roles
provider "aws" {
region = "us-east-1"
}
provider "aws" {
alias = "logging"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::210987654321:role/TerraformLoggingRole"
}
}Resources tagged with provider = aws.logging land in the logging account while the rest stay in the default account.
Limits to Remember
- Terraform needs every provider reference to be a fixed name. A variable cannot choose an alias.
- The
for_eachargument cannot select providers dynamically. - Many aliases make files harder to read. Group related resources into modules and pass one alias per module.
Key Points
- One provider block connects to one region or account.
- The
aliasargument creates an extra named connection. - Resources pick an alias with
provider = aws.west. - Modules receive aliases through the
providersmap. - Modules that need several connections declare
configuration_aliases. - Alias names must be fixed text, not variables.
