Safeguard
Supply Chain•

How do you try a pre-release Terraform module without surprising callers?

Terraform never selects a pre-release through a range operator, so a beta module must be named exactly. How to use that to trial changes safely.

Safeguard Security Team
4 min read

Publish the change as a pre-release version, such as 2.0.0-beta.1, and have the trial caller name that exact version. Terraform does not match pre-release versions through range operators, so no other caller receives it by accident. That makes pre-releases a safe way to test a breaking module change.

What Terraform does

HashiCorp's version constraints documentation says a pre-release version has a dash introduced suffix, such as 1.2.0-beta. You select one by setting the exact version with =, or by giving the exact version with no operator. It also states that Terraform does not match pre-release versions on the >, >=, <, <= or ~> operators.

So a caller using ~> 1.2 or >= 1.0 will not be moved onto 2.0.0-beta.1. Only a caller who writes the exact version will get it.

Why this suits shared modules

A shared module with many callers cannot test a breaking change on all of them at once. A pre-release lets one willing team try it first, with real configuration, while everyone else stays put. If it goes wrong, the trial team changes one line back.

Registry tags also need to be valid. For the public registry, HashiCorp requires release tags to be semantic versions with an optional v prefix. See versioning a shared module with semver.

A trial plan

  1. Merge the change to a branch through review, with owners approving.
  2. Tag a pre-release on that commit, for example 2.0.0-beta.1.
  3. Write release notes listing each breaking change and the edit needed.
  4. Pick one or two caller stacks that are not production critical.
  5. In each, set the module version to the exact pre-release and run terraform init. Changing a registry version requires rerunning init.
  6. Read the plan closely. Any replacement of existing objects needs a decision before release.
  7. Fix issues and tag the next pre-release, then repeat.
  8. When trials are clean, tag the final release and announce it.

Table: who gets what

Caller constraintReceives 2.0.0-beta.1?Receives 1.9.0?
Exact 2.0.0-beta.1YesNo
~> 1.8NoYes
>= 1.0NoYes
Git ref to a branchDepends on the branchDepends on the branch

The last row is the reason to prefer tagged versions over branch refs: a branch ref moves with every commit. See pinning module sources.

Cautions

After the trial

Move trial callers to the final version promptly, and remove any exact pre-release pins. A stale pin to a beta is easy to forget and hard to notice. A repository search for the suffix, run during review, catches strays.

Where Safeguard fits

Safeguard's SBOM and dependency scanning can inventory what your repositories declare, which helps find forgotten pins, and policies can gate pull requests that change them.

Quick check

Will a tilde arrow range pick up a beta module?

No. Terraform does not match pre-release versions on that operator or the other range operators.

How does a caller opt in to a pre-release?

By setting the exact version, with or without the equals sign, then rerunning terraform init.

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.