Learn OpenTofu - Exclusive Feature 2: Dynamic Provider Iteration (for_each on Providers)
Episode 7 of 21

Learn OpenTofu - Exclusive Feature 2: Dynamic Provider Iteration (for_each on Providers)

Terraform forbids using for_each and count on provider configurations, forcing multi-region setups to be written manually one by one. This episode covers OpenTofu's exclusive feature: dynamic provider iteration that loads many provider instances at once for concise multi-region and multi-account architectures.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Introduction

In the previous episode 6 we covered OpenTofu's first exclusive feature: native client-side state encryption — how the state file is encrypted on the client side before being sent to the remote backend, complete with AWS KMS and PBKDF2 key providers. Now that our most valuable asset is secure, we turn to the second practical problem that gives IaC engineers headaches: handling many regions and many cloud accounts.

Imagine your company rolls out an app to three AWS regions at once — Singapore for Southeast Asia, Virginia for the Americas, and Frankfurt for Europe. In classic Terraform, you'd have to write the provider "aws" block three times manually, or go through modules so the provider can be looped. Both approaches are tedious, repetitive, and prone to typos.

In this episode we cover OpenTofu's second exclusive feature: dynamic provider iteration — the ability to load many provider instances dynamically using for_each. You'll see how concise managing multi-region and multi-account becomes in HCL once this feature exists.

Main Discussion

The Traditional Terraform Limitation

In Terraform, meta-arguments like count and for_each work on resources, data sources, and modules — but they're forbidden on the provider block. Provider configuration is the only block that can't be looped.

As a consequence, for three regions you write:

Terraform: manual provider per region
provider "aws" {
  alias  = "singapore"
  region = "ap-southeast-1"
}
 
provider "aws" {
  alias  = "virginia"
  region = "us-east-1"
}
 
provider "aws" {
  alias  = "frankfurt"
  region = "eu-central-1"
}

Note the alias keyword — each provider instance needs a unique name so resources can reference it through the provider argument. Now imagine 10 regions, or 5 accounts times 5 regions: the blocks explode into dozens of tedious copies to write and maintain. Terraform's "official" solution is wrapping everything in a module called with for_each — elegant, but it still adds a layer of complexity.

OpenTofu's Exclusive Feature: Provider Iteration

OpenTofu removes that restriction. Provider blocks can now use for_each (and count) exactly like resources, with each.key and each.value available inside:

OpenTofu: dynamic provider iteration
provider "aws" {
  alias  = each.key
  region = each.value
} for_each = {
  singapore = "ap-southeast-1"
  virginia  = "us-east-1"
  frankfurt = "eu-central-1"
}

One block replaces three. Adding a new region is just adding one line to the for_each map — no more copy-pasting provider blocks.

Note

With for_each, each.key is the map key and each.value is its value. In the example above, the key becomes the provider alias and the value becomes the region — so resources can call aws.singapore, aws.virginia, and so on.

Resources still select which provider to use through the provider argument:

resource using an iterated provider
resource "aws_vpc" "singapore" {
  provider   = aws.singapore
  cidr_block = "10.0.0.0/16"
}

Multi-Account: Extended with assume_role

The real power shows when spreading across many accounts. Imagine running the same resource in the dev and prod accounts, each with a different role to assume:

Multi-account with assume_role
provider "aws" {
  alias  = each.key
  region = each.value.region
  assume_role {
    role_arn = "arn:aws:iam::${each.value.account_id}:role/DeployRole"
  }
} for_each = {
  dev  = { account_id = "111122223333", region = "ap-southeast-1" }
  prod = { account_id = "444455556666", region = "us-east-1" }
}

With a two-line map, OpenTofu loads two providers with different credentials for two accounts. Combine this pattern with for_each on resources and modules, and one map containing your entire environment layout drives everything else. This is the pattern that keeps "big workspaces" tidy.

Warning

Make sure every provider instance has a unique alias — use each.key to make it automatic. Without an alias, OpenTofu refuses to load multiple providers of the same type. Also, don't use for_each for truly identical provider configurations; use this feature to capture variation across regions or accounts.

Limitations & Migration Notes

  • Provider iteration adds one layer to the dependency graph; avoid reference cycles between looped providers.
  • Looped providers are still initialized via tofu init — per-account credentials are resolved at apply time, not init time.
  • After migrating from Terraform, old provider blocks can be refactored into this iteration form without changing any resources — the same alias keeps resources valid.
  • Verify the whole configuration with tofu validate after refactoring, then review the changes with tofu plan before applying.

Conclusion

Summary of episode 7:

  • Terraform forbids count and for_each on provider blocks, forcing manual writing per region or account.
  • OpenTofu supports for_each and count on providers, complete with each.key and each.value.
  • Multi-region becomes just one block plus a region map.
  • Multi-account combined with assume_role yields providers isolated per account.
  • Unique alias remains required so resources can reference provider instances.

The ability to load many providers dynamically opens the way to writing far more DRY infrastructure. In the next episode, episode 8, we'll cover Advanced Expressions, Built-in Functions & Loops — diving into OpenTofu's built-in functions, the count, for_each, and depends_on meta-arguments, lifecycle rules, and for expressions and ternary operators for writing expressive HCL. See you there!

Learn OpenTofu - Exclusive Feature 2: Dynamic Provider Iteration (for_each on Providers) | Learn OpenTofu