Correct way to handle provider versions in child modules

Hi, I am trying to understand how under Terraform v1.0+ the correct provider version should be specified for the child modules. A concrete example is any of the Terraform AWS modules. Here it says in the root module as well as in the child module:

versions.tf

terraform {
  required_version = ">= 0.13.1"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 3.28"
    }
  }
}

In comparison Azure only has an almost empty file in the root module level:

versions.tf

terraform {

}

Is this the way to go for custom modules? And if should I do the same for the provider block?

Hi @methylamin,

As a concession to backward-compatibility with modules written for Terraform v0.12 and earlier, Terraform v0.13 and later (including v1.0+) have a heuristic for automatically inferring provider requirements that aren’t explicitly declared:

For each resource block, take its resource type name (the first label, like aws_instance) and extract the prefix up to the first _. If that prefix doesn’t match one of the local names declared in the module’s required_providers block (or if the module doesn’t have one) then Terraform will infer one automatically, by placing the extracted prefix after hashicorp/ to create a source address, and by leaving version unset so as to take the latest available version of that provider.

In your second example here then, if there were a resource block elsewhere in the module with a type like azurerm_resource_group, Terraform would automatically infer a provider requirement declaration like this:

terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
    }
  }
}

If you are writing your own module and don’t have any need to support Terraform v0.12 and earlier then I would recommend writing out an explicit required_providers block like the one you showed with the hashicorp/aws provider. A good required providers block for a shared module should declare both the source address (hashicorp/aws in that case) and a minimum provider version that supports all of the features and behaviors the module is relying on.

Various modules in Terraform Registry were originally written to support older versions of Terraform and so often use some different approaches to remain compatible with those older versions. I assume that’s true for some of the modules you found by searching for “azurerm” in the public registry. Terraform v0.12 only partially understands this required_providers syntax, and earlier versions don’t understand it at all, so omitting it can be a reasonable strategy for a module that needs to support a broad set of Terraform language versions and which only relies on relatively-recent provider features such that it’s unlikely that a new user would select an incompatible old version of the provider.

1 Like