Files
opentf/website/docs/language/meta-arguments/module-providers.mdx
Diógenes Fernandes cb73ae4299 docs for provider for_each in modules and resources (#2696)
Signed-off-by: Diogenes Fernandes <diofeher@gmail.com>
2025-07-15 16:54:32 -03:00

212 lines
7.8 KiB
Plaintext

---
description: >-
The providers meta-argument specifies which provider configurations from a
parent module are available in a child module.
---
# The Module `providers` Meta-Argument
In a [module call](../../language/modules/syntax.mdx) block, the
optional `providers` meta-argument specifies which
[provider configurations](../../language/providers/configuration.mdx) from the parent
module will be available inside the child module.
```hcl
# The default "aws" configuration is used for AWS resources in the root
# module where no explicit provider instance is selected.
provider "aws" {
region = "us-west-1"
}
# An alternate configuration is also defined for a different
# region, using the alias "usw2".
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
# An example child module is instantiated with the alternate configuration,
# so any AWS resources it defines will use the us-west-2 region.
module "example" {
source = "./example"
providers = {
aws = aws.usw2
}
}
```
Each module in an OpenTofu configuration has its own separate namespace of
provider configurations, but a child module's namespace is populated with
configurations from the root module, either inheriting the default provider
configurations automatically or explicitly passing them from the parent
using the `providers` argument.
## Default Behavior: Inherit Default Providers
If the child module does not declare any [configuration aliases](../../language/modules/develop/providers.mdx#provider-aliases-within-modules),
the `providers` argument is optional. If you omit it, a child module inherits
all of the
[default provider configurations](../../language/providers/configuration.mdx#default-provider-configurations)
from its parent module. (Default provider configurations are any that don't
use the `alias` argument.)
If you specify a `providers` argument, it cancels this default behavior, and the
child module will only have access to the provider configurations you specify.
## Usage and Behavior
The `providers` argument uses a map-like syntax delimited by braces (`{`, `}`).
In the given mapping:
- The keys are the provider configuration addresses that will be used inside the
child module.
- The values are provider instance addresses from the parent module.
Both parts use
[provider instance reference syntax](../../language/providers/configuration.mdx#referring-to-provider-instances),
which for alternative provider configurations appears as `<PROVIDER NAME>.<ALIAS>`.
Within a child module, resources are assigned to provider configurations as
normal — either OpenTofu chooses a default based on the name of the resource
type, or the resource specifies an alternate configuration with the `provider`
argument. If the module receives a `providers` map when it's called, the
provider configuration names used within the module are effectively remapped to
refer the specified configurations from the parent module.
## When to Specify Providers
There are two main reasons to use the `providers` argument:
- Using different default provider configurations for a child module.
- Configuring a module that requires multiple configurations of the same provider.
### Changing Default Provider Configurations
Most re-usable modules only use default provider configurations, which they can
automatically inherit from their caller when `providers` is omitted.
However, in OpenTofu configurations that use multiple configurations of the
same provider, you might want some child modules to use the default provider
configuration and other ones to use an alternate. (This usually happens when
using one configuration to manage resources in multiple different regions of the
same cloud provider.)
By using the `providers` argument (like in the code example above), you can
accommodate this without needing to edit the child module. Although the code
within the child module always refers to the default provider configuration, the
actual configuration of that default can be different for each instance.
### Modules With Alternate Provider Configurations
In rare cases, a single re-usable module might require multiple configurations
of the same provider. For example, a module that configures connectivity between
networks in two AWS regions is likely to need both a source and a destination
region. In that case, the root module may look something like this:
```hcl
provider "aws" {
alias = "usw1"
region = "us-west-1"
}
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
module "tunnel" {
source = "./tunnel"
providers = {
aws.src = aws.usw1
aws.dst = aws.usw2
}
}
```
Non-default provider configurations are never automatically inherited, so any
module that works like this will always need a `providers` argument. The
documentation for the module should specify all of the provider configuration
names it needs.
### Module instances with differing provider instances
When you write a `provider` block using
[the `for_each` meta-argument](../../language/providers/configuration.mdx#for_each-multiple-instances-of-a-provider-configuration)
the provider configuration dynamically declares zero or more provider instances.
If you also write a `module` block that uses `for_each` you can set its provider
configuration addresses to refer to dynamically-chosen instances of a multi-instance
provider configuration, which allows instantiating a module once per provider
instance.
For example, you might instantiate a module for each of a number of different AWS
regions, declaring foundational infrastructure across all of the regions you use,
with the module itself using only one default provider configuration that differs
for each module instance:
```hcl
variable "aws_regions" {
type = map(object({
vpc_cidr_block = string
}))
}
provider "aws" {
alias = "by_region"
for_each = var.aws_regions
region = each.key
}
module "per_region" {
source = "./per-region"
# This expression filters var.aws_regions to include only
# the elements whose value is not null. Refer to the
# warning in the text below for more information.
for_each = {
for region, config in var.aws_regions : region => config
if config != null
}
providers = {
aws = aws.by_region[each.key]
}
region_name = each.key
vpc_cidr_block = each.value.vpc_cidr_block
}
```
The module in `./per-region` should be written so that all of its AWS resources
are bound to that module's default configuration for the AWS provider. The
`providers` argument in the `module` block ensures that each instance of the
module has its default configuration for the AWS provider bound to a different
instance of `aws.by_region`.
All instances of the module must refer to instances of the same provider
configuration: only the expression in brackets (`each.key` in the above example)
can vary between the instances of the module.
:::warning
**The `for_each` expression for a module must *be different from* the
`for_each` expression for its associated provider configuration.**
OpenTofu uses a provider instance to plan and apply _all_ actions related
to a module instance, including destroying a module instance that
has been removed from the configuration.
Therefore a provider instance passed into a child module that will declare
resources associated with that provider instance must always remain in the
configuration for at least one more plan/apply round after the module instance
has been removed, or OpenTofu will fail to plan to destroy the resource instances
declared in the module.
You can find more information on this constraint in
[Referring to Provider Instances](../../language/providers/configuration.mdx#referring-to-provider-instances).
:::
## More Information for Module Developers
For more details and guidance about working with providers inside a re-usable
child module, see
[Module Development: Providers Within Modules](../../language/modules/develop/providers.mdx).