Constraints and the Lock File

Scenario: Two engineers run the exact same .tf files on the exact same day and end up planning against two different provider releases, producing two different plans for what should be an identical change.

A version constraint (like ~> 1.0 in a required_providers block) defines a range of acceptable provider versions - it's a policy, not a specific choice. The dependency lock file (.terraform.lock.hcl, which init creates or updates) is different: it records the one exact version that was actually selected the last time someone ran init, plus cryptographic checksums to detect tampering or corruption. Constraint syntax is worth memorizing precisely because it directly controls how much drift is possible between two engineers' machines: ~> 1.4 (the "pessimistic constraint operator") permits any 1.x release from 1.4 upward but forbids 2.0, protecting you from an unexpected breaking major version; a bare >= 1.0 with no upper bound offers no such protection and can silently pull in a breaking 2.0 release on someone's next init -upgrade.

Always commit .terraform.lock.hcl to version control - it's the mechanism that makes "two engineers, same code, same provider version" actually true. Update it intentionally, by running terraform init -upgrade, then reviewing the diff and re-testing, rather than letting it drift silently. Note required_version (for the Terraform CLI itself) and provider version constraints are two separate settings solving the same kind of problem at two different layers.

Analogy: A version constraint is the list of ingredients a restaurant is willing to accept from any supplier ("any brand of tomato, as long as it's a certain grade"); the lock file is the receipt naming the exact batch, from the exact supplier, actually used in tonight's service. Two kitchens following the same acceptable-ingredients policy can still cook with different tomatoes unless they share the receipt.

A worked configuration

terraform {
  required_version = ">= 1.8, < 2.0"
  required_providers {
    fakecloud = {
      source  = "shellgenius/fakecloud"
      version = "~> 1.0"
    }
  }
}

In network-restricted environments (locked-down CI runners, air-gapped builds), teams often run a private provider mirror and verify checksums explicitly rather than reaching the public registry every time. Lock file entries are also platform-aware (they record checksums per OS/architecture), so a team whose engineers use different laptop architectures than their CI runner may need to deliberately populate multi-platform checksums, not just whatever their own machine produced.

Common mistakes in production

Goal: Do not delete .terraform.lock.hcl just to make an installation error go away. That error is usually telling you something real (a checksum mismatch, an unreachable mirror) - deleting the file hides the symptom while leaving every collaborator free to select a different version from that point on. Reinforce this lesson in the tf-version-lockfile Terraform lab. Open /labs/terraform and choose slug tf-version-lockfile; the lab runs real Terraform against the offline FakeCloud provider.