linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Knowledge base
  • Cheat sheet
  • Capstone
  • Interview prep
home/terraform/kb/Terraform basics/tf-lockfile

kb/core ── Terraform basics ── beginner

.terraform.lock.hcl: pinning provider versions

The lockfile pins the exact provider versions and their hashes, so you and CI always run the same build. It is created on terraform init and updated through init -upgrade. Commit it to git.

view as markdownaka: terraform-lockfile, provider-lockfile

What the lockfile is

.terraform.lock.hcl is a file in the project root where terraform records: "for the current configuration I downloaded the AWS provider version 5.62.0 with these hashes." The lockfile appears after the first [[tf-init|terraform init]] and is then updated by the rules below.

Its purpose is determinism. Without a lockfile, two engineers or CI can download different minor versions of a plugin from the same code and end up with different plans. With a lockfile, everyone gets the same build until someone bumps it explicitly.

Example contents:

hcl
provider "registry.terraform.io/hashicorp/aws" {
  version     = "5.62.0"
  constraints = "~> 5.60"
  hashes = [
    "h1:abc123...",
    "h1:def456...",
    "zh:0123...",
    "zh:4567...",
  ]
}
  • version is the exact installed version.
  • constraints is the expression from required_providers. The lockfile remembers it so that on init -upgrade it looks for a new version within the same constraint.
  • hashes are two kinds of hashes. h1: is the hash of the whole zip archive. zh: is the hash of a specific binary for one platform.

When the lockfile changes

  • First terraform init creates it from scratch, with the version set to the latest one that fits the constraint.
  • terraform init with no flags: if the lockfile already has an entry, terraform tries to honor it. If the hashes do not match, it fails.
  • terraform init -upgrade goes to the registry for fresh versions within the same constraint and rewrites the lockfile.
  • The required_providers block changes: if you add a provider, change a constraint, or change a source, the next init writes or rewrites the matching blocks.
  • terraform providers lock is a deliberate update of the hashes for several platforms (see below).

No command ever edits the lockfile "by accident." If the file changed, one of these scenarios happened.

Multi-platform hashes

When init runs on macOS, the lockfile gets the hashes of binaries for darwin_arm64 or darwin_amd64. When the same project later runs in a Linux CI, terraform on that platform will not find the hash it needs and will fail.

The fix is to add the hashes for every platform you need up front:

bash
terraform providers lock \
  -platform=linux_amd64 \
  -platform=linux_arm64 \
  -platform=darwin_amd64 \
  -platform=darwin_arm64

The command goes to the registry for the hashes of each platform and appends them to the lockfile. One run is enough when you set up the project, or when you add a new platform to the command.

To commit or not

Commit it. The lockfile is part of the project's source of truth, on a par with the .tf files. Without it you lose the main benefit: repeatability.

In .gitignore you list only .terraform/ (the provider cache), not .terraform.lock.hcl. A common beginner mistake is to add *.lock to gitignore and hide the lockfile. After that, complaints of "it works on my machine but not in CI" become regular.

What to do on a hash error

The error text from init:

Error: Failed to install provider
Error while installing hashicorp/aws v5.62.0: the local package for
registry.terraform.io/hashicorp/aws 5.62.0 doesn't match any of the
checksums previously recorded in the dependency lock file

Causes and fixes:

  • init ran on a new platform. The fix is terraform providers lock -platform=... (see above), then commit the updated lockfile.
  • You changed the provider version without -upgrade. The fix is terraform init -upgrade.
  • A registry mirror served a different binary. This is serious. Check whether the provider was swapped in your corporate mirror.

Lockfile conflict on merge

Two people on one branch changed required_providers. They got a git conflict in .terraform.lock.hcl. What to do:

  1. Do not try to merge the hash blocks by hand. They are fragile.
  2. Take either version (or git checkout --ours/--theirs).
  3. Run terraform init -upgrade. It rewrites the lockfile for the current HCL.
  4. Commit the result.

Pitfalls

  • The lockfile does not block major bumps on init -upgrade. If the constraint is >= 5.0 (with no upper bound), -upgrade will happily move you to 6.x. To prevent that, write pessimistic constraints like ~> 5.60 (see tf-version-constraints).
  • The lockfile does not pin modules. Only providers. Modules are cached in .terraform/modules/ without hashes, and module versions have to be controlled through a [[tf-init-modules|version constraint in the module block]].
  • .terraform.lock.hcl is edited only by tooling. Do not edit it by hand. If you really must, delete it and run init -upgrade.

§ команды

bash
terraform init

Creates the lockfile on the first run; on later runs, it checks that the hashes of what was downloaded match.

bash
terraform init -upgrade

Updates providers within the constraints and rewrites the lockfile.

bash
terraform providers lock -platform=linux_amd64 -platform=darwin_arm64

Append hashes for several platforms. Needed when the team works on different operating systems or architectures.

bash
rm .terraform.lock.hcl && terraform init

Reset the lockfile. Use only when you know what you are doing: after this the version is pinned again and may turn out newer than you expect.

§ см. также

  • tf-initterraform init: the first command in any projectterraform init downloads the provider plugins (AWS, GCP, and so on), creates a lockfile that pins their versions, and prepares the working directory. Without it, neither plan nor apply will run.
  • tf-version-constraintsVersion constraints in Terraform: required_version and providersrequired_version pins which versions of terraform may run this code. required_providers.version does the same for providers. The pessimistic operator ~> 5.60 is the standard: it allows minor updates and blocks major ones.
  • tf-provider-blockThe provider block: who Terraform will callThe provider block configures the plugin: which AWS region to talk to, which endpoints to use, which credentials to take. One block per provider is usually enough.
  • tf-init-modulesHow terraform init pulls in modulesWhen your HCL has a module block, terraform init downloads the module source (from a registry, git, or a local folder) into .terraform/modules/. This course does not write modules; this article is an overview of how the mechanics work.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies