| --- | |
| description: >- | |
| Use providers within modules. Learn about version constraints, aliases, implicit inheritance, and passing providers to modules. | |
| --- | |
| # Providers Within Modules | |
| In a configuration with multiple modules, there are some special considerations | |
| for how resources are associated with provider configurations. | |
| Each resource in the configuration must be associated with one provider | |
| configuration. Provider configurations, unlike most other concepts in | |
| OpenTofu, are global to an entire OpenTofu configuration and can be shared | |
| across module boundaries. Provider configurations can be defined only in a | |
| root module. | |
| Providers can be passed down to descendent modules in two ways: either | |
| _implicitly_ through inheritance, or _explicitly_ via the `providers` argument | |
| within a `module` block. These two options are discussed in more detail in the | |
| following sections. | |
| A module intended to be called by one or more other modules must not contain | |
| any `provider` blocks. A module containing its own provider configurations is | |
| not compatible with the `for_each`, `count`, and `depends_on` meta-arguments. | |
| Provider configurations are used for all operations on associated resources, | |
| including destroying remote objects and refreshing state. OpenTofu retains, as | |
| part of its state, a reference to the provider configuration that was most | |
| recently used to apply changes to each resource. When a `resource` block is | |
| removed from the configuration, or a dynamic instance of a resource is removed | |
| by modifying the value assigned to the `count` or `for_each` meta-argument, | |
| this record in the state will be used to locate the appropriate configuration | |
| because the resource instance's `provider` argument (if any) will no longer be | |
| present in the configuration. | |
| As a consequence, you must ensure that all resources that belong to a | |
| particular provider instance are destroyed before you can remove that | |
| provider instance from your configuration. If OpenTofu finds a resource instance | |
| tracked in the state whose provider instance is no longer declared in the | |
| configuration then it will return an error during planning, prompting you | |
| to reintroduce the provider instance. | |
| ## Provider Version Constraints in Modules | |
| Although provider _configurations_ are shared between modules, each module must | |
| declare its own [provider requirements](../../../language/providers/requirements.mdx), so that | |
| OpenTofu can ensure that there is a single version of the provider that is | |
| compatible with all modules in the configuration and to specify the | |
| [source address](../../../language/providers/requirements.mdx#source-addresses) that serves as | |
| the global (module-agnostic) identifier for a provider. | |
| To declare that a module requires particular versions of a specific provider, | |
| use a `required_providers` block inside a `terraform` block: | |
| ```hcl | |
| terraform { | |
| required_providers { | |
| aws = { | |
| source = "hashicorp/aws" | |
| version = ">= 2.7.0" | |
| } | |
| } | |
| } | |
| ``` | |
| A provider requirement says, for example, "This module requires version v2.7.0 | |
| of the provider `hashicorp/aws` and will refer to it as `aws`." It doesn't, | |
| however, specify any of the configuration settings that determine what remote | |
| endpoints the provider will access, such as an AWS region; configuration | |
| settings come from provider _configurations_, and a particular overall OpenTofu | |
| configuration can potentially have | |
| [several different configurations for the same provider](../../../language/providers/configuration.mdx#alias-multiple-provider-configurations). | |
| ## Provider Aliases Within Modules | |
| To declare multiple configuration names for a provider within a module, add the | |
| `configuration_aliases` argument: | |
| ```hcl | |
| terraform { | |
| required_providers { | |
| aws = { | |
| source = "hashicorp/aws" | |
| version = ">= 2.7.0" | |
| configuration_aliases = [ aws.alternate ] | |
| } | |
| } | |
| } | |
| ``` | |
| The above requirements are identical to the previous, with the addition of the | |
| alias provider configuration name `aws.alternate`, which can be referenced by | |
| resources using the `provider` argument. | |
| If you are writing a shared module, constrain only the minimum | |
| required provider version using a `>=` constraint. This should specify the | |
| minimum version containing the features your module relies on, and thus allow a | |
| user of your module to potentially select a newer provider version if other | |
| features are needed by other parts of their overall configuration. | |
| It is not currently possible to pass a provider configuration with multiple | |
| instances (that was declared using `for_each`) as a whole to a child module, | |
| although it is valid for the parent module to assign a single dynamic instance | |
| of a provider configuration to each instance of the module. | |
| ## Implicit Provider Inheritance | |
| For convenience in simple configurations, a child module automatically inherits | |
| [default provider configurations](../../../language/providers/configuration.mdx#default-provider-configurations) from its parent. This means that | |
| explicit `provider` blocks appear only in the root module, and downstream | |
| modules can simply declare resources for that provider and have them | |
| automatically associated with the root provider configurations. | |
| For example, the root module might contain only a `provider` block and a | |
| `module` block to instantiate a child module: | |
| ```hcl | |
| provider "aws" { | |
| region = "us-west-1" | |
| } | |
| module "child" { | |
| source = "./child" | |
| } | |
| ``` | |
| The child module can then use any resource from this provider with no further | |
| provider configuration required: | |
| ```hcl | |
| resource "aws_s3_bucket" "example" { | |
| bucket = "provider-inherit-example" | |
| } | |
| ``` | |
| We recommend using this approach when a single configuration for each provider | |
| is sufficient for an entire configuration. | |
| :::warning Note | |
| Only provider configurations are inherited by child modules, not provider source or version requirements. Each module must [declare its own provider requirements](../../../language/providers/requirements.mdx). This is especially important for non-HashiCorp providers. | |
| ::: | |
| In more complex situations there may be | |
| [multiple provider configurations](../../../language/providers/configuration.mdx#alias-multiple-provider-configurations), | |
| or a child module may need to use different provider settings than | |
| its parent. For such situations, you must pass providers explicitly. | |
| ## Passing Providers Explicitly | |
| When child modules each need a different configuration of a particular | |
| provider, or where the child module requires a different provider configuration | |
| than its parent, you can use the `providers` argument within a `module` block | |
| to explicitly define which provider configurations are available to the | |
| child module. For example: | |
| ```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 | |
| } | |
| } | |
| ``` | |
| [The `providers` argument within a `module` block](../../../language/meta-arguments/module-providers.mdx) | |
| is similar to | |
| [the `provider` argument within a `resource` block](../../../language/meta-arguments/resource-provider.mdx), | |
| but is a mapping rather than a single string because a module may | |
| contain resources from many different providers. | |
| The keys of the `providers` map are provider configuration names as expected by | |
| the child module, and the values are the names of corresponding configurations | |
| in the _current_ module. | |
| Once the `providers` argument is used in a `module` block, it overrides all of | |
| the default inheritance behavior, so it is necessary to enumerate mappings | |
| for _all_ of the required providers. This is to avoid confusion and surprises | |
| that may result when mixing both implicit and explicit provider passing. | |
| Additional provider configurations (those with the `alias` argument set) are | |
| _never_ inherited automatically by child modules, and so must always be passed | |
| explicitly using the `providers` map. 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 | |
| } | |
| } | |
| ``` | |
| The subdirectory `./tunnel` must then declare the configuration aliases for the | |
| provider so the calling module can pass configurations with these names in its `providers` argument: | |
| ```hcl | |
| terraform { | |
| required_providers { | |
| aws = { | |
| source = "hashicorp/aws" | |
| version = ">= 2.7.0" | |
| configuration_aliases = [ aws.src, aws.dst ] | |
| } | |
| } | |
| } | |
| ``` | |
| Each resource should then have its own `provider` attribute set to either | |
| `aws.src` or `aws.dst` to choose which of the two provider configurations to | |
| use. |