Skip to main content
In this lesson we cover provider versions and version constraints in OpenTofu. Providers are published to the public registry and distributed as plugins. By default, running tofu init downloads the latest provider versions required by your configuration, but pinning or constraining versions is important to maintain reproducible, stable deployments.

Example resource

This simple example uses the local provider to write to a file:

Default behavior of tofu init

When you run tofu init, OpenTofu locates and installs provider plugins. By default it selects the latest compatible versions and records those selections in a lock file:
Include the generated .terraform.lock.hcl in version control to ensure consistent provider selection across runs and machines.
Because provider behavior may change between releases, you should explicitly pin or constrain provider versions to protect your configuration from unexpected changes.

Pinning an exact provider version

To pin a provider to a single specific version, declare it in the terraform block using required_providers with source and version:
Running tofu init with that configuration installs the exact version you requested:

Using version constraints

If you want flexibility while still controlling upgrades, use version constraints. The version attribute accepts constraint expressions similar to common package managers. Examples below show how to express different constraints while using the same local_file resource.
  1. Not-equal constraint (!=)
This tells OpenTofu to avoid version 2.4.1; it will select the newest available version that does not match the excluded version.
  1. Less-than or greater-than constraints
This requires a version strictly less than 2.4.1 (for example 2.4.0 or earlier).
This requires a version strictly greater than 2.3.0 (for example 2.3.1, 2.4.0, etc., when available).
  1. Combining constraints (comma-separated)
This allows versions greater than 2.2.3 and less than 2.4.1 but explicitly excludes 2.4.0. OpenTofu will pick the highest available version that satisfies all constraints (for example, 2.3.0).

The pessimistic operator (~>)

The pessimistic operator ~> is useful when you want to allow non-breaking updates but prevent potentially breaking ones. Its behavior depends on the specificity of the version you supply.
  1. ~> 2.2
~> 2.2 is equivalent to ”>= 2.2.0, < 3.0.0” — this permits any 2.x version at or above 2.2.0 (2.2.1, 2.3.0, 2.4.1, etc.) but prevents upgrades to 3.x.
  1. ~> 2.2.0
~> 2.2.0 is equivalent to ”>= 2.2.0, < 2.3.0” — this allows patch-level updates within the 2.2 series, but not newer minor versions (2.3.x or later).

Quick reference: constraint operators

Best practices

  • Use an exact version when you require strict reproducibility across environments.
  • Use range comparisons or the pessimistic operator to permit safe, non-breaking updates while avoiding unintended major upgrades.
  • Exclude known-broken versions with != when necessary.
  • Always commit .terraform.lock.hcl to version control so subsequent runs use the same provider selections.
When adjusting provider constraints, test upgrades in a staging environment before applying changes in production. Provider releases can introduce behavior changes even when the API surface looks compatible.

Watch Video