Set provider version constraints to say what you accept, and commit the .terraform.lock.hcl file so every run installs the same provider and checks its checksum. HashiCorp's documentation says to include the lock file in version control so changes to external dependencies go through code review like configuration.
Constraints say what is allowed
Terraform's version constraint syntax includes the exact match with no operator, exclusion with the not equal operator, comparison operators, and the pessimistic operator. The documentation defines that last operator, written ~>, as allowing only the right-most version component to increment. For example ~> 1.0.4 allows 1.0.5 and 1.0.10 but not 1.1.0, and ~> 1.1 allows 1.2 and 1.10 but not 2.0.
Terraform uses versions that meet all applicable constraints. For plugins and modules it uses the newest installed version that meets them, and downloads the newest match if none is installed. So a constraint alone does not freeze anything. A new provider release inside the range will be picked up the next time Terraform has to download one.
The lock file records what was chosen
Terraform creates or updates the dependency lock file each time you run init. It records the selected provider versions and checksums. The documentation says to commit it, so you can discuss potential changes to external dependencies in code review.
| Item | Job | Commit it? |
|---|---|---|
| required_providers constraint | Allowed range | Yes |
| .terraform.lock.hcl | Exact selection and checksums | Yes |
| Local provider cache | Downloaded binaries | No |
Checksum verification, and its meaning
Terraform verifies that each installed package matches at least one checksum recorded in the lock file and errors if none match. The documentation describes this as a trust on first use approach. When you add a provider the first time, you can verify it in whatever way you or your regulations require, and then trust that choice from then on.
So the lock file protects you from a provider package changing after you recorded it. It does not tell you whether the package was trustworthy when you first accepted it.
Practical steps
- Add a constraint for every provider and module, using the pessimistic operator on a minor version for providers you trust to follow their versioning.
- Run init, review the lock file, and commit it.
- When Terraform says it changed the provider selections in the lock file, treat that as a change to review, not noise.
- Upgrade deliberately in a branch, review the diff, run plan, and merge.
- Record checksums for each platform your team and CI use, so developers on different machines do not rewrite the file back and forth.
- Restrict who can approve lock file changes, since they decide which provider code runs with your cloud credentials.
Modules
The constraint behavior applies to modules too. Pin remote modules to a version you have read, not to a branch. Terraform's lock file is described in the documentation for providers, so check module sources separately.
Where Safeguard fits
Safeguard offers policies, gates and guardrails that can be applied in review and CI, and dependency scanning and SBOM generation for what your code pulls in. A free scan is at gold.safeguard.sh/scan.
Try it yourself
Open the gate demo and imagine a lock file change arriving in the same pull request, waiting for a reviewer.
Click through it at your own pace, or open it full screen.
Quick check
Does a version constraint pin the provider?
No. Terraform uses the newest version that meets the constraints. The lock file is what records the exact selection.
What is the trust on first use approach?
Checksums are recorded the first time you add a provider, and later installs must match them. You decide how to verify it the first time.
Sources
Last reviewed: 19 October 2026.