Safeguard
Developer Tools•

What does terraform init -upgrade change for modules?

terraform init -upgrade moves installed modules to the newest version your constraint allows. When it runs, what it touches and how to review the result.

Safeguard Security Team
3 min read

terraform init -upgrade moves installed modules to the latest version your constraints allow. Plain terraform init keeps what is already installed unless you changed a module source or version. So a range constraint only picks up new releases when someone runs the upgrade, which makes that command a review point.

What the documentation states

HashiCorp's module configuration page says that changing a registry version or a source requires rerunning terraform init, and that terraform init -upgrade moves installed modules to the latest version allowed by the constraint. For Git sources without a ref, Terraform clones and uses the default branch referenced by HEAD, and a ref pins to a branch, SHA-1 hash or tag.

Three situations

What you doResult
Run terraform init with nothing changedInstalled module versions stay as they are
Edit version or source, run terraform initNew source or version is installed
Run terraform init -upgrade with a range constraintNewest version within the range is installed

The upgrade flag is where silent drift enters a configuration that uses ranges. The range was agreed when the pin was written. The new version was not reviewed by anyone.

Why shared repositories care

In a shared repository with a range such as ~> 1.4 on an internal module, the next person to run upgrade pulls whatever the module team released last. That is acceptable if the module team follows semantic versioning consistently. HashiCorp says to use version ranges for modules your organization maintains if it does. If it does not, use exact versions.

For third party modules, HashiCorp advises pinning specific versions so updates happen when convenient. See pinning Terraform modules.

How to make upgrades reviewable

  1. Run upgrade on a branch, never directly on the default branch.
  2. Commit the resulting changes and open a pull request.
  3. In the pull request, read the release notes of each module that moved.
  4. Run a plan and read it. Any replaced object needs a human decision.
  5. Check that provider selections did not change unexpectedly. The lock file records those. See what the lock file protects.
  6. Merge only after required reviewers approve.

A scheduled bot can do steps 1 and 2 for you. See Dependabot for Terraform.

CI considerations

In CI, avoid running upgrade inside the same job that applies. The apply should use what was reviewed. See lock file read only in CI. A pipeline that upgrades and applies in one step makes the unreviewed version the production version.

What it does not tell you

The command does not say whether a new module version is safe or whether its release notes list every change. It shows only the selection. Judging the change is still work for reviewers, and a clean semver history does not replace reading the diff.

Where Safeguard fits

Safeguard's policies and gates can require reviewers and checks on pull requests that change module versions, and its evidence automation can record approvals.

Quick check

Does plain init upgrade modules?

No. Per HashiCorp, you need to rerun init when a source or version changes, and use the upgrade flag to move to the latest allowed version.

Is a git module without a ref pinned?

No. Terraform uses the default branch referenced by HEAD, so it can change.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.