In Terraform, how do you create resources in two AWS regions from a single configuration, and how does an individual resource choose the second region?
answer
- region belongs to the provider, not the resource
- two regions means two configurations
- the second block gets a name
- provider = aws.eu on the resource
- unaliased block is the implicit default
basics
~20 sDeclare a second aws provider block with an alias argument and its own region, then set the meta-argument provider = aws.<alias> on each resource that belongs in that region. Resources with no provider argument use the unaliased default block.
solid answer
~40 sRegion is a property of the *provider configuration*, not of the resource, so touching two regions means having two configurations. You declare one `provider "aws"` block without an `alias` — that becomes the default for every `aws_*` resource — and a second block with `alias = "eu"` and `region = "eu-west-1"`. Any resource or data source that should land in the second region gets the `provider` meta-argument pointing at it: `provider = aws.eu`, written as an unquoted reference rather than a string. Terraform records which provider configuration owns each resource in state, so a resource does not silently move regions if you edit the blocks. Child modules do not inherit aliased configurations — those must be passed in explicitly with the module's `providers` argument.
code
hcl · 17 linesprovider "aws" {
region = "us-east-1"
}
provider "aws" {
alias = "eu"
region = "eu-west-1"
}
resource "aws_s3_bucket" "primary" {
bucket = "example-primary-bucket"
}
resource "aws_s3_bucket" "replica" {
provider = aws.eu
bucket = "example-replica-bucket"
}go deeper
Be able to write the two provider blocks from memory: one plain, one with alias and its own region, then provider = aws.eu on the resource. Say clearly that region is set on the provider, not the resource.
Explain that the unaliased block is the implicit default chosen from the resource type prefix, that aliased ones are opt-in only, and that data sources need the same argument or they query the wrong region.
Show that state binds each resource to a provider configuration, so removing or renaming a block strands existing resources, and discuss when many aliases in one root module beat one parameterised root module applied per region.
Own the estate-level call: aliases put several regions in one state and one blast radius, while a region-per-root-module layout trades verbosity for isolated failure domains and independent apply cadence. Be ready to justify which one your organisation standardises on.
## The problem aliases solve In the AWS provider, `region` is an argument of the **provider configuration**, not of the resource. `aws_s3_bucket` has no `region` argument you can set per bucket. So a configuration that has to create something in `us-east-1` and something else in `eu-west-1` needs *two provider configurations* of the same provider — and therefore a way to tell them apart. That way is `alias`. ## Default vs aliased configurations A `provider "aws"` block with no `alias` is the **default configuration** for that provider inside the module where it is written. Terraform picks a provider for each resource from the resource type's prefix: `aws_instance` implies the `aws` provider, `google_compute_instance` implies `google`. With no further instruction it uses the default configuration. (If you never declare a provider block at all, Terraform implies an empty one, which for AWS means everything comes from environment variables and the shared config file.) Adding `alias = "eu"` creates an **additional** configuration that is never chosen automatically. Something must ask for it by name. ```hcl provider "aws" { region = "us-east-1" } provider "aws" { alias = "eu" region = "eu-west-1" } ``` ## Selecting a configuration on a resource Every resource and data source accepts the `provider` meta-argument. Its value is a **reference**, of the form `<provider name>.<alias>` — unquoted, not a string, and not an expression: ```hcl resource "aws_s3_bucket" "primary" { bucket = "example-primary" # default provider -> us-east-1 } resource "aws_s3_bucket" "replica" { provider = aws.eu # -> eu-west-1 bucket = "example-replica" } ``` The same argument works on `data` blocks, which matters more than people expect: a `data "aws_ami"` lookup without `provider = aws.eu` will search the *default* region and hand you an AMI ID that does not exist in the other one. ## What Terraform remembers State records, per resource instance, which provider configuration manages it. That is why the association is not cosmetic: if you delete or rename a provider configuration that existing resources still point at, Terraform refuses to plan with a "Provider configuration not present" error, because it no longer knows how to reach those objects even to destroy them. Removing a region is therefore a two-step job — destroy or move the resources first, then delete the block. ## You may have as many as you need — but they are static Aliases are just names, so a replicated three-region layout is three blocks plus a default. What you cannot do is compute the choice: `provider = aws[var.region]` is invalid, because provider configurations are resolved before expressions are evaluated. The provider's *arguments* can use variables (`region = var.region` is fine), which is why the common alternative to many aliases is one root module parameterised by region, applied once per region against separate state. ## Aliases and modules Default (unaliased) configurations are inherited by child modules automatically. Aliased ones are not. A `module` block that needs one passes it explicitly through the `providers` map, and the child declares that it expects it. A reusable module should never declare its own `provider` block — that hard-codes the region into the module and blocks the caller from using `count` or `for_each` on it. ## Interview framing The crisp version of this answer is three sentences: region lives on the provider, a second region means a second provider configuration distinguished by `alias`, and a resource opts into it with `provider = aws.eu`. Everything else — cross-account variants using `assume_role` per alias, passing them into modules, the removal constraint — hangs off that skeleton.
- If a resource has no provider argument, how does Terraform decide which configuration manages it?It derives the provider from the resource type prefix — `aws_instance` means the `aws` provider — and uses that provider's default (unaliased) configuration in the module where the resource is declared. If no provider block exists at all, Terraform implies an empty configuration, so the AWS provider falls back to environment variables and the shared config file.
- Does the provider meta-argument work on data sources too, and why does that matter?Yes, and forgetting it is a classic bug. A `data "aws_ami"` or `data "aws_vpc"` block without `provider = aws.eu` queries the default region, so you get an ID that is meaningless in the other region and the apply fails — or worse, silently attaches the wrong object. Whenever a resource is aliased, check its lookups are aliased too.
- What happens if you delete an aliased provider block while resources in state still reference it?Terraform fails planning with a "Provider configuration not present" error. State records the provider configuration for each resource, and without it Terraform cannot even destroy them. You must destroy or move those resources while the configuration still exists, then remove the block.
saying these in an interview costs you the question
- Thinks one provider block can cover several regions at once
- Looks for a region argument on the resource itself
- Quotes the reference, writing provider = "aws.eu"
- Assumes child modules inherit aliased providers automatically
- Says you must run Terraform separately for each region