Stable Language Evolution
Minimum Supported Rust Version
A project's Minimum Supported Rust Version (MSRV) is the oldest stable Rust compiler release on which the crate promises to compile and pass its test suite. Establishing a clear MSRV policy—and verifying it automatically in Continuous Integration—helps downstream enterprise users, Linux distribution packagers, and long-term support (LTS) projects upgrade safely.
Common MSRV Policies in the Rust Ecosystem:
1. Rolling Window Policy (e.g., "Latest Stable minus N releases"):
- N = 4 releases (~6 months of support) or N = 8 releases (~1 year of support)
- Bumping MSRV is treated as a Minor SemVer bump (`0.2.0 -> 0.3.0` or `1.4.0 -> 1.5.0`)
2. Edition-Aligned Policy:
- Tracks the baseline compiler of the current Rust Edition (e.g., `1.85.0` for Rust 2024)
3. Latest Stable Policy (Typical for internal applications & leaf binaries):
- Always tracks current stable via `rust-toolchain.toml`
Discovering and Verifying Your Crate's MSRV (cargo-msrv)
What if you aren't sure which minimum version of rustc your crate currently requires, or you want to verify that a pull request didn't accidentally call a brand-new standard library method stabilised after your declared rust-version?
- Automated binary search with
cargo-msrv(cargo install cargo-msrv --locked): Performs a binary search across historicalrustuptoolchains to find the exact minimumrustcversion that compiles your crate (cargo msrv find) or verifies your declaredrust-version(cargo msrv verify). - Clippy MSRV lint (
clippy::incompatible_msrv): Whenrust-versionis set inCargo.toml(ormsrvis set inclippy.toml), runningcargo clippyon the latest compiler warns you immediately if you call any standard library function that was stabilized after your declaredrust-version!
#![warn(clippy::incompatible_msrv)]
/// If `Cargo.toml` declares `rust-version = "1.85"`, Clippy checks every std call
/// against its `#[stable(since = "...")]` metadata even when you develop on a newer compiler!
pub fn parse_hex_u16(input: &str) -> Option<u16> {
let stripped = input.strip_prefix("0x").unwrap_or(input);
u16::from_str_radix(stripped, 16).ok()
}
fn main() {
assert_eq!(parse_hex_u16("0x1a2b"), Some(0x1a2b));
println!("Parsed hex u16 under MSRV check: {:#x}", parse_hex_u16("0x1a2b").unwrap());
}
Parsed hex u16 under MSRV check: 0x1a2b
Testing MSRV in Continuous Integration
In GitHub Actions, add a dedicated MSRV job that reads rust-version directly from Cargo.toml so it never drifts out of sync with your manifest:
msrv:
name: MSRV Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install MSRV toolchain from Cargo.toml
uses: dtolnay/rust-toolchain@master
with:
# Or pin explicitly to match `rust-version` in Cargo.toml:
toolchain: "1.85.0"
- run: cargo check --workspace --all-targets --all-features