Skip to content

Instantly share code, notes, and snippets.

Last active September 4, 2023 11:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielhenrymantilla/9b59de4db8e5f2467ed008b3c450527b to your computer and use it in GitHub Desktop.
Save danielhenrymantilla/9b59de4db8e5f2467ed008b3c450527b to your computer and use it in GitHub Desktop.
MSRV Policy

MSRV Policy

The MSRV (Minimum Supported Rust [toolchain] Version) policy of my crates for a semver-compatible bump is the following:

stable - 9

More precisely:

  • Patch1 bump ⇒ same MSRV

  • Minor2 bump ⇒ MSRV may increase, but not beyond 1-year-old stable (stable - 9)

    This means that technically (based on a fixed interpretation of MSRV), I may break MSRV!
    If this is a problem, use a .lock file (or, worse, a ~ tilde Cargo.toml version requirement)

Note: the initial MSRV of a new major bump or newly created crate may be more recent than stable - 9

  • For instance, as of May 2023, I am using Rust 1.65 (6-month old stable) for new crates / major semver bumps, since I find GATs to be a major milestone of the language.

Consequences for you, (potential) user/dependent of my crate

  • 🐣 If you keep your toolchain lagging less than a year behind stable (i.e., stable - 9), you can let Cargo semver pick whichever specific version it wants, it won't break you

  • 👴 If you are using a "very old" (more than 1 year old) Rust toolchain, then:

    you should have your Cargo.lock file tracked by git/your repository!

About tracking Cargo.lock

This, much like formatting and linting, thus requires an extra CI step that enforces it being done, by running, for instance, cargo update -w -v --locked (dev-wise / git hook-wise, run it without the --locked to actually update the .lock files so that they are up-to-date with the .toml files).

You may be tempted not to do so due to some misguided advice from the official Rust/Cargo guidelines. They are wrong! A Cargo.toml does NOT define a dependency tree, it just constrains the range of possible ones! The one actually picked is "arbitrary" (depends on the exact state of the at the time Cargo resolves it): without a .lock file, your builds will not be reproducible:

  • thereby breaking git bisect or any other form of "travel back to time" functionality,
  • and in case a semver-compatible dependency breaks something (due to a genuine semver error, or due to "acceptable semver breakage", such as MSRV itself), which will happen, or in case of yanking, your build will break, and may also be annoying for you to fix back.
  • Eventually, you may even be tempted to start using =-pinned versions in your Cargo.toml, which in the long run does way more harm than good.
  • (if you have many Cargo.lock files in your repo you may need to adjust/fix your [workspace])

If you really want to avoid keeping the .lock file tracked, then you can kind of get away with it if my crate is on a major.minor.patch version. In that case, you could use a tilde requirement, which shall only allow patch bumps, instead of the default (implicit-caret requirement, which allows patch and minor bumps).

  • I do not recommend this since any kind of non-(caret-)semver constraint in a Cargo.toml file can make your crate incompatible with other ones for (downstream) dependents; and these dependents may not have the same Rust compiler constraints that you have, so the whole resulting situation becomes quite silly.


  1. major.minor.(patch + 1)

  2. major.(minor + 1).0 or 0.major.(minor + 1).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment