Best provider.tf (versions.tf) placement

As @maxb noted, the answer here depends on what you are intending to place in each file, but for the sake of discussion let’s assume a relatively common convention:

  • versions.tf contains a terraform block that contains a required_providers block that specifies the providers that the module uses and the earliest version of each provider the module is known to be compatible with.

    This information is scoped to one module at a time, so when writing it you should only think about what the current module needs and not consider what any other modules are compatible with.

  • providers.tf contains one or more provider blocks that actually instantiate the providers, specifying the configuration to use for each.

    Provider configurations have global scope, so the root module configures these on behalf of all downstream modules and so must consider the needs of the entire effective configuration.

If you are intending to follow that convention, then every one of your modules would have a versions.tf file, and each one should describe only what that one module needs. For example, if one of your modules uses a provider feature that is relatively new then it would probably specify a different minimum version than another module that uses provider features that have been available for a long time.

You should have providers.tf only in modules that you intend to use as root modules. The others should inherit or be passed configurations from their callers.

Some exceptions to these guidelines:

  • If you have a module that you know has been broken by a later major version of a provider and you aren’t yet ready to upgrade it, you would typically specify an upper limit on the version constraint in required_providers for that particular module, so Terraform won’t try to select a newer version that’s incompatible.
  • Some legacy modules include provider blocks even though they aren’t root modules. I would not recommend writing any new modules like that, but it is technically still allowed – with various caveats – for backward compatibility.

When you run terraform init in a root module you will get one more file generated automatically: .terraform.lock.hcl. This file tracks Terraform’s decisions about which version of each provider to use to satisfy all of the modules’ version constraints, and so you should also add this to your version control to ensure that later provider releases with breaking changes can’t break your setup. Terraform will select a new version only if you explicitly ask it to by running terraform init -upgrade.

2 Likes