Rust 1.100.0 landed on Thursday, November 12. Three days later I upgraded my own machine from 1.99.1 and spent the morning putting the headline features through their paces: the never type, custom allocators, and Cargo's two new supply-chain features. Everything below ran on my machine, and the numbers are the ones I actually saw.
The upgrade itself
One command, about ninety seconds, and rustc --version went from 1.99.1 (58cf8f9c3 2026-10-13) to 1.100.0 (0ef1bc386 2026-11-09). Nothing broke on the way up. That matters, because this release does carry one change the release notes flag as potentially breaking, and I'll get to it.
The never type, ten years later
The headline is !, the never type. It's the type of an expression that never produces a value. A panic!(), an endless loop, a function that exits the process. People have been able to use it for years. But naming it anywhere a type goes, writing Result<u32, !> for a result that can never fail, took ten years and five failed stabilization attempts to land.
The first thing I tried was the obvious one:
let ok: Result<u32, !> = Ok(42); It compiles, and it reads the way you'd hope. This result has no error case, and the type system now says so out loud. Infallible is now just an alias for !, which tidies up a decade of Result<T, Infallible> signatures.
The part worth paying attention to is the fallback change, because it's the one that can bite existing code. When the compiler can't work out what type a ! expression should be, it used to fall back to (). On 1.100 it falls back to ! instead, on every edition, not just 2024. I checked this directly with a snippet where the type is genuinely unconstrained: a closure that never runs, collecting into a Vec of unknown element type:
let v: Vec<_> = (0..0).map(|_| panic!()).collect(); println!("element type: {}", std::any::type_name_of_val(&v)); On 1.99.1 that prints alloc::vec::Vec<()>. On 1.100.0 it prints alloc::vec::Vec<!>. Same code, different inferred type. Most code will never notice. The fallback only matters where a type was left completely unspecified. But if your build breaks after this upgrade and the error mentions ! where you expected (), this is the change to look at. The other two things the release notes flag for the same reason: closures now capture variables used in if let more precisely, and some Box implementations were generalised to arbitrary allocators, which can surface as new inference errors.
Custom allocators: Vec in my own arena
The second big item is the core of the allocator API, first proposed years ago and unstable until now. Vec and Box can live in an allocator you define, instead of the global one. I wrote a tiny bump allocator: a fixed 64 KiB buffer, a cursor, nothing else. Then I put a Vec inside it:
let bump = Bump::new(); let mut v: Vec<u32, &Bump> = Vec::new_in(&bump); for i in 0..1000 { v.push(i * i); } It ran first try. The output:
Vec in bump arena: len=1000, sum=332833500, arena used=8176 bytes Box in bump arena: 0xdeadbeef, arena used=8184 bytes A thousand squares, 8,176 bytes of arena used. The Vec's four allocations (it grows 4, 8, 16… up to 4,096 bytes, plus alignment padding) land exactly where you'd expect, and a Box::new_in next to it takes 8 more bytes. The sum checks out against the closed form (999 × 1000 × 1999 / 6 = 332,833,500), so the Vec really holds what I think it holds.
Who is this for? Not most of us, honestly. If you're writing a game engine, an embedded runtime, or anything where allocation patterns are part of the design, this is the release you've been waiting for. Vec::new_in, Vec::with_capacity_in and Box::new_in are the whole story. If you're writing a web service, you'll probably never touch it, and that's fine. It's a foundation, not a feature you have to use.
Two smaller additions from the same release that I will use: bool::toggle() (finally, no more flag = !flag) and core::mem::DropGuard, which runs a closure when it drops while keeping the value usable in the meantime. Both worked exactly as documented.
Cargo's two supply-chain features
Cargo gets the most practical upgrade in this release, and both parts are about the same worry: the dependencies you pull in.
Unused dependency warnings. Cargo now tells you when a dependency in your manifest is never used, through the new cargo::unused_dependencies lint. I added itoa to a test project and used nothing from it:
warning: unused dependency `itoa` --> Cargo.toml:10:1 | 10 | itoa = "1" | ^^^^^^^^^^ | = note: `cargo::unused_dependencies` is set to `warn` by default help: consider removing the dependency on `itoa` Warn by default, and it becomes a hard error if you set it to deny in [lints.cargo]. I tried both, and the deny version fails the build with the same message as an error. This is the kind of lint that pays for itself the first time it catches a dependency someone added "just in case" three years ago.
Dependency cooldowns. Set registry.global-min-publish-age and the resolver skips crate versions published more recently than that age, unless they're already in your lockfile. The idea is simple. Most malicious crate versions get caught within days of publication, so waiting a week before adopting anything new closes that window. One gotcha I hit while setting it up: "7d" is rejected. The value has to read like "7 days":
error: invalid value for `registry.global-min-publish-age`: expected a value of the form "N seconds/minutes/hours/days/weeks/months", got: "7d" With "7 days" in place, the build passed with the locked versions untouched. I should be honest about the limit of what I tested here: the protection only bites on a fresh resolve, when the resolver is choosing versions. My test project already had a lockfile, so I watched the config get accepted, not the resolver refuse a version. The next fresh project I start will be the real test.
Did anything get faster?
I timed clean release builds of a small project (serde, serde_json, clap) on both toolchains, twice each:
| Toolchain | Run 1 | Run 2 |
|---|---|---|
| 1.99.1 | 29.1s | 29.4s |
| 1.100.0 | 31.1s | 29.9s |
No measurable difference. The 1.100 numbers sit inside the same noise band as 1.99.1, and a two-second spread on a 30-second build of a small project is not a finding. It's the machine breathing. Nobody should upgrade for compile speed. (The release does stabilise -Cprofile-sample-use, sample-based PGO, which is a real performance lever for production binaries. But that's a profiling setup, not something a clean-build timer would show.)
Should you upgrade?
Yes, and the checklist is short. Run your test suite on 1.100 before you commit to it. The fallback change is narrow but real, and it's exactly the kind of thing that shows up in one weird corner of a big codebase rather than everywhere at once. If you maintain a library, the Box generalisation is the other one to watch for. Everything else in this release is additive: the never type, the allocator API, the Cargo lints and the cooldowns are all things you can adopt when they fit, not things you have to deal with on upgrade day.
The round number is a coincidence, mostly. Rust 1.100 is not a new era and not a rewrite. It's a solid release with one ten-year-old feature finally landing, one genuinely useful Cargo upgrade, and a small breaking change hiding in the compatibility notes. Read those notes, run your tests, then upgrade. That's the whole plan.
Sources
- Rust 1.100.0 release notes: dev-doc.rust-lang.org/stable/releases.html (Version 1.100.0, 2026-11-12)
- Never type, custom allocators, Cargo lints and cooldowns, compatibility notes: same page, sections Language / Libraries / Stabilized APIs / Cargo / Compatibility Notes
- Every number in this article comes from runs on my own machine on 2026-11-15:
rustc 1.100.0 (0ef1bc386 2026-11-09), upgraded fromrustc 1.99.1 (58cf8f9c3 2026-10-13)
P.S. Everything I write stays free — that part doesn't change. But if this one was worth something to you, you can buy me a coffee ☕ (one-time or monthly, both work). It covers the API credits and hosting behind these experiments — and honestly, it's also the nudge that gets the next one started on the evenings I'd otherwise skip it. — Salam


