Rust-version in a workspace

If you have a workspace with a bunch of crates in it, how do you maintain the rust-version fields?

In general I try to keep rust-version as low as possible, and only increase it if I actually use later language features or std features, or if dependencies require it. I do this on a crate-by-crate basis. This tends to lead to different rust-versions in different crates within the same workspace.

Where it gets a little murky to me is when I want to update dependencies. If I run cargo update --verbose and it tells me that a dependency is being held back due to MSRV, I figure that I need to look up which workspace crates use this dependency and update their MSRV until the resolver is happy and updates the dependency. For small workspaces this isn't a problem, but I just noticed this issue in a rather large project and figuring out which crates need to bump rust-version to satisfy the resolver is a little bit of a chore, and I'm not looking forward to this becoming a recurring maintenance thing.

I've thought about setting rust-version globally instead (in the workspace's Cargo.toml). The upside would be that I only need bump it once. The (very major) downside is that MSRV will be higher than it needs to be for some crates. This doesn't bother me for internal crates, but I won't want to do this for published crates.

How do you manage rust-version in workspace crates?

My initial opinion on this is that that your MSRV policy is not internally consistent, and if you fix that, you will not need to do this extra work.

If your goal is to maintain the property “the rust-version is set as low as it possibly can be, to make my libraries as compatible as possible”, then you shouldn’t be increasing the rust-version because of dependency versions that cargo update will update to, because dependents on the older Rust version will use older versions of your dependencies and that works out fine for them — assuming no bugs they care about in those libraries; if there were, they would need a newer Rust toolchain version anyway.

What you can do instead is use cargo update --ignore-rust-version.[1]

But, if you’re serious about compatibility, you should be testing with both configurations. It does no good to declare a low rust-version if that configuration doesn’t actually work. In fact, you should have separate test runs for three different configurations:

  • cargo update --ignore-rust-version: test that the very latest deps work.
  • cargo update: test that the latest deps at your rust-version work. If this fails while the previous one succeeds, then it is because of a bug (or behavior change) in your dependencies, and so you need to increase rust-version and also the version requirements in your [dependencies].
  • cargo +nightly update -Zdirect-minimal-versions: test that your library works with the oldest versions of its dependencies that it claims to support. If this fails, then you need to increase the version requirements in your [dependencies].

  1. I haven’t used this option myself, but maybe I should start. ↩︎

I don't micro-manage it.

The worst reasonable(ish) case of being stuck on an old Rust version is Debian Stable. Currently that's 1.85 (Trixie), so that's what I set when I need broad Linux compatibility. Fortunately these days Rust is complete enough that working even with the Debian's version is fine.

"latest - 6" seems to be a popular policy, and covers most Linux distros.

Otherwise "latest - 3" is fine for rustup users (gives extra buffer in case rustc has some regression that takes 1-2 releases to sort out).