Differentiating between terraform providers in modules

I have a Terraform module (let’s call it module1) that utilizes a google and google-beta provider of version 2.20.

I intend to call this module from another one (let’s call it module2) that (for some reason) has a restriction on the google and google-beta providers’ configuration, as follows:

provider "google-beta" {
  version = "< 2.12"
}

provider "google" {
  version = "< 2.12"
}

Is there a way to make module2 instantiate module1 (more or less as follows) and keep its providers’ restriction?

(let’s assume the below snippet is from main.tf of module2


module mymodule {
  source        = "../../../path/to/module1"
}

provider "google-beta" {
  version = "< 2.12"
}

provider "google" {
  version = "< 2.12"
}

…while at the same time, module1 gets to keep its own version of google providers?

Hi @pkaramol,

Because providers are a concept that crosses module boundaries in Terraform, the dependencies on providers for a configuration are the combination of all of the dependencies of all of the modules.

However, when a child module has a dependency on a provider that it’s expecting to inherit from the parent module, it’s better to declare the dependencies using required_providers in the terraform block:

terraform {
  required_providers = {
    "google"      = "< 2.12"
    "google-beta" = "< 2.12"
  }
}

The difference between the above and the version argument in a provider block is that a provider block’s primary purpose is to create a provider configuration, which is not something a child module should generally be doing. The version argument in the provider block is primarily for backward-compatibility with older Terraform versions, though it also serves as a convenient shorthand for root modules where we often have both a provider configuration and a version constraint for each provider.

If you place required_provider blocks in your modules then Terraform will require that all the constraints be met, across the entire configuration. However, to avoid creating a sort of “dependency hell” situation where your module requirements combine to effectively exclude all available versions, the documentation recommends using only >= constraints in shared modules, unless there is a specific known incompatibility with later versions. That then combines with a ~> constraint in the root module to set both upper and lower bounds.

There is no way to use different versions of a particular provider for different modules in your configuration. Provider configurations pass between module boundaries, so the entire configuration must agree on a provider version so that they can share a configuration for that version.

1 Like