In today’s blog post, we will discuss terraform provider meta argument. A provider is basically a plugin that understands how to interact with a specific service (like AWS, Azure, Google Cloud, Kubernetes, GitHub, etc.). While Terraform automatically uses the default configuration for a declared provider, there are many scenarios (for example, you have multiple cloud regions to connect, multiple roles to authenticate etc.) where you need finer control. This is where the you need to understand provider
meta-argument to configure and control your terraform landscape.
What is the provider Meta-Argument?
The provider
meta-argument is a special argument that you can include within a resource
, data source
, or module
block. Its role is to explicitly instruct that specific instance of a resource, data source, or module to use a non-default configuration of a given provider.
Its syntax is straightforward:
provider = <PROVIDER_TYPE>.<ALIAS_NAME>
Here:
<PROVIDER_TYPE>
is the name of the provider (e.g.,aws
,azurerm
,google
).<ALIAS_NAME>
is thealias
you assigned to a specific provider configuration in your root configuration.
By default, if you do not specify the provider
meta-argument, Terraform will use the default configuration for that provider type (i.e., the provider block without an alias
).
Why Use the provider Meta-Argument?
The primary use cases for the provider
meta-argument revolve around scenarios where you need to interact with the same cloud or service in multiple, distinct ways within a single Terraform configuration.
- Multi-Region Deployments: This is perhaps the most common use case. You might want to deploy an S3 bucket in
us-east-1
and an EC2 instance ineu-west-1
within the same Terraform state. - Multi-Account Deployments: Many organizations use separate cloud accounts for different environments (e.g.,
dev
,test
,prod
) or for different teams. Theprovider
meta-argument allows you to target these different accounts from one configuration. - Multiple Configurations for the Same Provider: Even within a single region or account, you might need to use the same provider with different authentication contexts (e.g., two AWS provider blocks using different IAM roles or access keys).
How to Use the provider Meta-Argument (Examples)
To use the provider
meta-argument, you first need to define multiple configurations for your provider using the alias
attribute within the provider
block.
Example 1: Using provider with resource
Step 1: Define Aliased Provider Configurations
Let us set up multiple AWS provider configurations, one for us-east-1
and another for us-west-2
.
# provider.tf
# Default provider configuration (no alias) - often for your primary region/account
provider "aws" {
region = "ap-south-1" # Our primary region in Kolkata, West Bengal, India
}
# Aliased provider for US East (N. Virginia)
provider "aws" {
region = "us-east-1"
alias = "virginia" # A descriptive alias
}
# Aliased provider for US West (Oregon)
provider "aws" {
region = "us-west-2"
alias = "oregon" # Another descriptive alias
}
# Example: Another aliased provider for a different account/role (assuming credentials are set up)
# provider "aws" {
# region = "ap-south-1"
# alias = "secondary_account"
# assume_role {
# role_arn = "arn:aws:iam::123456789012:role/TerraformExecutionRole"
# }
# }
Step 2: Use the provider Meta-Argument in Resources
Now, you can explicitly direct resources to use these aliased configurations.
# main.tf
# This S3 bucket will be created in the default region (ap-south-1)
resource "aws_s3_bucket" "default_bucket" {
bucket = "my-default-ap-south-1-bucket-example"
acl = "private"
tags = { Name = "DefaultBucket" }
}
# This S3 bucket will be created in us-east-1 (Virginia)
resource "aws_s3_bucket" "my_virginia_bucket" {
provider = aws.virginia # Explicitly use the 'virginia' alias
bucket = "my-virginia-bucket-example-unique-12345"
acl = "private"
tags = { Name = "VirginiaBucket" }
}
# This EC2 instance will be created in us-west-2 (Oregon)
resource "aws_instance" "my_oregon_instance" {
provider = aws.oregon # Explicitly use the 'oregon' alias
ami = "ami-0abcdef1234567890" # Replace with a valid AMI for us-west-2
instance_type = "t2.micro"
tags = { Name = "OregonInstance" }
}
Example 2: Using provider with Data Sources
The provider
meta-argument works identically with data
blocks. This is useful for fetching information from one region/account to be used in another.
# main.tf
# Fetch latest Amazon Linux 2 AMI from us-east-1 (Virginia)
data "aws_ami" "latest_virginia_ami" {
provider = aws.virginia # Fetch from Virginia
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
# Create an EC2 instance in us-west-2 (Oregon) using the AMI ID from Virginia
resource "aws_instance" "oregon_instance_with_virginia_ami" {
provider = aws.oregon # Instance in Oregon
ami = data.aws_ami.latest_virginia_ami.id # AMI ID sourced from Virginia
instance_type = "t2.small"
tags = { Name = "OregonInstanceWithVirginiaAMI" }
}
Example 3: Passing Provider Configurations to Modules
When using modules, you often want the resources within the module to be deployed using a specific provider configuration defined in the calling (root) module. You can do this by using the providers
block within the module
definition.
# root_module/provider.tf
# Define provider configs in the root module
provider "aws" {
region = "us-east-1"
alias = "dev_us_east"
}
provider "aws" {
region = "us-west-2"
alias = "prod_us_west"
}
# root_module/main.tf
# Call a module and pass the specific provider alias to it
module "dev_application" {
source = "./modules/application"
environment = "dev"
# This maps the 'aws' provider used *within* the module
# to the 'aws.dev_us_east' provider defined in the root.
providers = {
aws = aws.dev_us_east
}
}
module "prod_application" {
source = "./modules/application"
environment = "prod"
providers = {
aws = aws.prod_us_west
}
}
# modules/application/main.tf (Inside the module)
variable "environment" {
type = string
}
resource "aws_instance" "app_server" {
# This resource will implicitly use the 'aws' provider that was passed
# from the parent module (either aws.dev_us_east or aws.prod_us_west)
ami = "ami-0abcdef1234567890" # Replace with a valid AMI for both regions
instance_type = "t2.micro"
tags = {
Name = "app-server-${var.environment}"
Environment = var.environment
}
}
In the example above, module.dev_application
will deploy its aws_instance.app_server
in us-east-1
, while module.prod_application
will deploy its instance in us-west-2
, all managed from a single root configuration.
Best Practices for Using the provider
Meta-Argument
- Clear Aliasing Convention: Use descriptive and consistent aliases (e.g.,
virginia
,oregon
for regions;dev_account
,prod_account
for accounts) to make your configurations readable. - Default Provider for the Majority: If most of your resources will reside in one specific region or account, keep that provider configuration as the default (without an
alias
). Only explicitly use theprovider
meta-argument for the exceptions. - Explicit Module Provider Passing: When calling modules, always be explicit about which provider configuration the module should use via the
providers
block. This makes module behavior predictable and reusable. - Readability Over Redundancy: Do not use the
provider
meta-argument if it is not strictly necessary (e.g., if a resource would already default to the desired provider). This keeps your code clean.
Conclusion
The provider
meta-argument is a key concept for managing complex, geographically distributed, or multi-account infrastructure with Terraform. By understanding how to define aliased provider configurations and explicitly assign them to your resources, data sources, and modules, you gain control over where and how your infrastructure is provisioned.
Related Items:
depends_on
– https://ckdbtech.com/mastering-terraform-depends_on-meta-argument/lifecycle
– https://ckdbtech.com/mastering-terraform-lifecycle-meta-argument/for_each
– https://ckdbtech.com/mastering-terraform-for_each-meta-argument/count
– https://ckdbtech.com/mastering-terraform-count-meta-argument/
Author

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins.
In my free time, I write blogs on ckdbtech.com