What are provider aliases, and how do they interact with modules?

5 minadvancedterraformprovidersaliasesmodules

Quick Answer

A provider alias (`provider "aws" { alias = "secondary"; region = "eu-west-1" }`) lets a single configuration configure the *same* provider multiple times — e.g., to manage resources in two AWS regions or two accounts — and resources select one via `provider = aws.secondary`. Modules don't implicitly inherit the root's aliased providers; you must explicitly pass them through a module's `providers = { aws = aws.secondary }` map (and the module must declare a matching `configuration_aliases` entry), which keeps multi-provider wiring explicit rather than implicit/magic.

Detailed Answer

Provider aliases solve a specific problem: what if a single configuration needs to talk to the same provider (e.g., AWS) more than once, with different settings — different regions, different accounts, different credentials?

Declaring an alias

provider "aws" {
  region = "us-east-1"          # the "default" provider
}

provider "aws" {
  alias  = "eu"
  region = "eu-west-1"
}

A resource then opts into the non-default provider explicitly:

resource "aws_instance" "eu_replica" {
  provider      = aws.eu
  ami           = var.ami_id_eu
  instance_type = "t3.micro"
}

Common use cases: multi-region deployments (a primary region plus a DR region), cross-account resources (a shared logging account vs. the workload account), or managing resources across two different Terraform-supported platforms configured as the same provider type but distinct endpoints.

Passing aliased providers into modules

By default, a child module does not automatically inherit the root's aliased providers — each module gets its own implicit default provider configuration inherited from the caller, but extra aliases must be passed explicitly. The module must first declare that it accepts one, via configuration_aliases:

# modules/replica/main.tf
terraform {
  required_providers {
    aws = {
      source                = "hashicorp/aws"
      configuration_aliases = [aws.eu]
    }
  }
}

resource "aws_instance" "replica" {
  provider = aws.eu
  # ...
}

Then the caller wires it up explicitly:

module "replica" {
  source = "./modules/replica"
  providers = {
    aws     = aws          # default
    aws.eu  = aws.eu        # explicitly passed alias
  }
}

Why the explicitness matters

This design is deliberate: implicit provider inheritance across module boundaries would make it easy to lose track of which region/account a deeply-nested resource actually targets. Requiring configuration_aliases and an explicit providers = { ... } map means anyone reading the module call can see exactly which provider configurations flow into it — critical for auditing multi-account/multi-region setups where "which account did this resource land in?" is a serious operational question, not just a style preference.

Related Resources