Trust is earned, not given

A different perspective

2026-09-15 · Projects

Rust, part 15: the state of Rust today — 1.98, the supply chain, and the borrow checker's next act

Part 15from the Rust series · 15 parts in all

The stable compiler is at 1.98 as this is written, with the 2024 edition a year and a half behind us. The interesting questions in 2026 are no longer "is Rust viable" — that was settled — but which of the remaining rough edges are actually being worked on, and which have turned out to be permanent.

What is genuinely settled now

The supply chain, which is the real 2026 conversation

Almost every production Rust question I get asked now is about dependencies, not about borrows:

# The baseline hygiene commands, all worth wiring into CI.
cargo deny check advisories bans licenses sources
cargo audit
cargo tree -d          # duplicated majors - the upgrade you have been avoiding
cargo semver-checks    # does this release actually break your public API?

# And the lockfile rule that matters more than any tool:
# a binary commits Cargo.lock. A library does not.

The surface area is the point: a typical service has hundreds of transitive crates, and that is a fact to manage rather than a reason to avoid Rust. The tools above are mature, and cargo-vet — recording that a specific human reviewed a specific version — is what the high-assurance end of the ecosystem uses instead of pretending review happened.

Polonius, and why the borrow checker is still being rewritten

The borrow checker the compiler ships is not the one its designers want. The current implementation uses a "mid-point" dataflow analysis whose limitations are the reason for the error messages that make no sense: the pattern that makes you clone a Vec unnecessarily, or refuse a conditional return of a reference obtained before a mutation. The replacement, Polonius, has been in development for years, and is now available as an opt-in on the newer compilers rather than a default.

What it fixes is narrow and real:

fn get_or_insert(map: &mut HashMap<String, String>, key: &str) -> &str {
    if let Some(v) = map.get(key) {
        return v;                     // borrowed map immutably, returned it
    }
    map.insert(key.to_string(), String::new());   // needs a mutable borrow
    map.get(key).unwrap()                          // today: may need restructuring
}

Under the current analysis this can be rejected because it considers the first borrow live across the insert; Polonius reasons about which paths reach which borrows and accepts it. That is a genuine improvement to code people actually write, and it is the change most likely to make Rust feel different in the next few years. Treat the timing as in-progress: it is opt-in now, and I would not schedule a redesign around it.

What I would tell someone starting today

  1. Learn ownership properly, once (part 1). Everything else is downstream of it, and the people who fight Rust are usually fighting this.
  2. Use thiserror in libraries and anyhow in binaries (part 2), and resist reaching for Rc<RefCell> to make the compiler stop complaining.
  3. Write the straightforward safe code, and keep unsafe in one module behind a safe API with documented invariants (part 11).
  4. Pick the runtime deliberately, and remember that in async Rust nothing is concurrent unless a combinator or a spawn says so (part 7).

Fifteen parts ago this series started with three rules about ownership. The through-line is that Rust's difficulty is front-loaded and its benefits are structural: the borrow checker, the type system and the error model all move work from production to the compiler. Fifteen years of industry experience says that is the right direction to move work in.