05 Aug 2026
Planet Mozilla
Firefox UX: Let your designs fail for the right reasons
How AI-assisted native prototypes changed what usability testing could show me.
If you've ever simplified an interaction just to make a prototype manageable, you've probably felt the tension between what you designed and what the prototype could actually support. The risk is that when a design fails in usability testing, you can't always tell why. Was the experience itself the problem, or was it really the prototype getting in the way: a missing connection, a laggy transition, a path you didn't build?
I ran into this while working on Report Broken Site for Firefox Android, and it led me to a different way of prototyping: building directly inside the real app with AI (Claude), so the test reflects native fidelity rather than a simulation of it. That's when I started worrying just about the design failing, and not the prototype.
Feature: Report Broken Site
Reaching limits of walled prototypes
In tools like Figma, prototyping requires anticipating every possible interaction and defining it explicitly. For the user to feel the true experience, each path needs to be connected, each transition set, and each variation accounted for. As complexity grows, it tends to increase the cost of maintaining it: screens multiply, connections become fragile, and animations become tedious to maintain.
At some point, you're no longer designing the experience. You're managing the prototype.
E.g. Changing the animation for one node, requires updating it everywhere manually.
To cope, we simplify the prototype. We reduce the number of paths, guide users through predefined flows, and limit what they can do on the prototype. The result is what I've started thinking of as a walled prototype - like a walled garden: a bounded space where users can move, but only within the paths we've pre-defined.
Some designers might argue that Figma's recent additions of variables and advanced logic solve this problem. However, even with these tools, the designer is still building and managing the prototype. Figma prototypes simulate a system; it is not the system itself or a part of it. These prototypes have been useful, but they have also shaped the participant testing experience in ways that haven't always been obvious.
When the logic of a feature is handled by manual connections, the canvas quickly turns into spaghetti of fragile dependencies.
Prototypes shape participant behavior
This becomes especially noticeable in usability testing. Test participants tend to recognize when they are interacting with a prototype, and that awareness can change how they behave. They may hesitate to explore, follow the perceived intent of the task, or tap around when they get stuck.
For example, to keep a prototype manageable, I might only make a few issue types selectable. But then participants are doing two things at once: deciding what they want to do and guessing what the prototype will allow. Their feedback can become shaped by the prototype's limits, not just the design - like a visitor to the walled garden checking which paths are actually open to them.
That constraint can be useful in early concept testing, where a narrower path helps focus the conversation. It becomes more limiting when we are trying to understand how the full experience behaves.
Research and practice have long acknowledged that prototype fidelity and testing setup can influence participant behavior. But in practice, many workflows still rely on constrained, screen-to-screen simulations.
I've often wondered:
How a user's perceived experience might change if they weren't encountering the feature in the isolation of a walled prototype?
From walled to native fidelity prototypes
Designing and prototyping is often described in terms of fidelity - from low-fidelity sketches to high-fidelity designs ready for dev handoff. That framing focuses on how closely we represent the product, but not necessarily how the experience itself behaves.
As building realistic interactions becomes easier using AI, it may now be possible to move beyond simulating flows in Figma and towards observing how people actually behave. So, alongside designing it in Figma, I built the feature directly into a local version of the Firefox Android app using Claude. It wasn't straightforward at first, but even the friction of getting it working revealed things I wouldn't have seen in a Figma prototype.
When I did this, I noticed there were no predefined paths to manage or fragile connections to maintain. The experience felt more continuous, allowing users to move more freely, not just within the feature, but within the app itself. I started thinking of these as prototypes with native fidelity - native to the app, native to the device, and aligned with how users expect interactions to behave.
When prototypes need to handle dynamic behavior
The difference between the two types of prototypes is not just theoretical; it starts to change what the experience can support. In walled prototypes, content is often fixed, and interactions move users between predefined screens. While this works for simple flows, it becomes harder to represent how interfaces behave when content needs to update dynamically based on user interaction.
In the Report Broken Site feature, this was important. A walled prototype struggles with:
- Capturing website data: Depending on the browsing tab, metadata like the URL, screenshot, browser info, and tracking data needs to be captured and reflected back to the user.
- URL editing: Simulating real text entry, cursor movement, and auto-correct behavior.
- Branching logic: If a user selects "Site doesn't load" as issue type, the details are optional, but if they choose "Something else," details become required.
- Error handling: For "Something else," the system must validate input length in the description box and show an error if it's insufficient.
Have you ever run into interactions like these and found yourself simplifying them, just to make the prototype manageable?
When I built it directly using Claude, the native fidelity prototype was able to handle metadata capture, text input, and branching logic more naturally.
The native fidelity prototype inherits native behaviors like metadata capture, keyboard interactions, and dynamic state changes.
The environment is part of the experience
Another challenge is the environment in which the prototype is experienced. In walled prototypes, layouts are often fixed, and responsiveness is limited. Differences in device size, orientation, or performance can introduce inconsistencies that don't reflect the intended final experience.
In practice, this can show up as:
- Oversized UI elements on larger devices as the prototype was created for an average phone size.
- Laggy interactions on slower networks as Figma prototypes fail to be responsive sometimes.
- Layouts that don't adapt as expected because of the constraints of the prototyping environment.
When the interaction is built directly in the app, the experience inherits the native environment of the device. Layouts respond to screen size, interactions feel more consistent, and the overall experience is closer to what users would encounter in the final product. This could reduce the likelihood of testing interfaces being mistaken for design issues.
Tradeoffs and new realities
This approach introduces its own challenges. First time setup for a designer is complex, and navigating the codebase and working through unfamiliar tools takes effort.
Using Claude on the Firefox for Android codebase in Android Studio to build the prototype.
Adopting this approach requires a shift in the UX designer's toolkit. It raises the barrier to entry by requiring baseline comfort with the terminal, build environments, and IDEs. But it also allows designers to move beyond "faking the experience" in Figma prototypes and start building directly in the app.
Building the prototype this way also changes how the work evolves. Instead of worrying about defining everything upfront, requirements tend to emerge through interaction -i.e. edge cases, missing states, and unclear behaviors as the experience is built. In Figma, many of these details are easy to overlook; when you create a prototype by building directly, they become easier to find.
Of course, this realism has its limits. While the experience feels like a continuous system rather than a sequence of steps, I haven't yet connected it to a backend, pulled in APIs, or tested cross-device capabilities across mobile, tablet, and desktop. I'm still at the start of this exploration. What I want to understand next is how native fidelity prototypes change the testing environment itself: whether participants explore differently, whether failures are easier to interpret, and what new friction this approach introduces for designers and teams.
Start failing for the right reasons
To put it simply: if prototypes constrain user behavior, they may also shape the insights we get from usability testing.
For Report Broken Site, the value of the native prototype was not just that it handled more states. It gave me a more honest way to sit with the experience before putting it in front of participants. I could edit the URL, switch issue types, trigger validation, and move around the app as the feature would exist in context. Because this was a mobile experience, that context mattered: I could test it on a real device, with real navigation patterns, real input behavior, and the surrounding app experience intact. Those details helped me look past whether the prototype was working and focus more directly on whether the experience was working.
That is what I mean by letting the design fail for the right reasons: understanding whether an experience fails because of the design itself, not because of a missing screen-to-screen connection, bad transition, or laggy Figma prototype. The next step is to test whether this translates into different participant behavior and more useful usability insights.
Originally published on medium.com.
05 Aug 2026 5:46pm GMT
This Week In Rust: This Week in Rust 663
Hello and welcome to another issue of This Week in Rust! Rust is a programming language empowering everyone to build reliable and efficient software. This is a weekly summary of its progress and community. Want something mentioned? Tag us at @thisweekinrust.bsky.social on Bluesky or @ThisWeekinRust on mastodon.social, or send us a pull request. Want to get involved? We love contributions.
This Week in Rust is openly developed on GitHub and archives can be viewed at this-week-in-rust.org. If you find any errors in this week's issue, please submit a PR.
Want TWIR in your inbox? Subscribe here.
Updates from Rust Community
Official
- Enabling the next iteration of the borrow checker on nightly
- Funding team progress update
- rust-lang/rust is adopting an LLM policy
- All Hands 2026 retrospective
Newsletters
Project/Tooling Updates
- Kevat 0.4.0 - fast, resumable copy and move to external drives, now with a GUI on all three platforms
- kache 0.13.0: keying the env vars proc-macros read
- kobe 101: lease a Kubernetes cluster, don't create one
- Rewriting FalkorDB in Rust: Make It Work, Make It Stable
- Announcing
webrtcv0.20.0: Async-Friendly, Runtime-Agnostic WebRTC on Sans-I/O Corertc - Proxelar 0.5.0: sessions, rules, and more ways to capture traffic
- mirador 1.0.0: a personal terminal dashboard
- BitFun 0.2.15: an open-source desktop AI agent built on a Rust runtime
- mvis v0.5.0: CI/CD Profiling & Allocation Histograms
- multicalc 0.9.0: scientific computation for embedded and robotics systems
- Auto-correcting wrong-layout typing on Wayland is nearly impossible. We did it anyway
- wimux 0.1.0: a native Windows terminal multiplexer
- amtr: a btop-style context-window monitor for Claude Code sessions, and the forensic autopsy of its own 153-hour build
- RSigma v0.20.0 release
- The State of RSigma, and Part Two: The Loop
Observations/Thoughts
- How Firecracker microVMs work under the hood to sandbox untrusted code and AI agents
- Faster floating point math with Rust's new API
- Rust MEMS drivers: 3 reasons to try and adopt our new sensor driver
- The Bedrock of Software Design | Alex Fedoseev
- Tail-Call Interpreters in Rust
- How to speed up the Rust compiler in July 2026
- Sovereign Tech Fellowship for Rust maintenance (June-July 2026 report)
- An old-new take on argument parsing in Rust
- Stateless Servers, Stateful Payloads: Sessions vs Continuations, Measured in Rust
- [video] Rust in the age of Generative AI with Niko, Allen & Zeeshan
- [audio] Rust in Production S06 E09: JetBrains with Orhun Parmaksız
- Work-Stealing vs. Executor-Per-Thread: Evaluating different HTTP server workloads with Tokio, Smol and Glommio
- Your
#[target_feature(enable = "avx2")]does nothing onx86_64-unknown-uefi - Three bugs my AI agents couldn't fix
Rust Walkthroughs
- Blinking an LED on STM32 Blue Pill (STM32F103C8T6) with Embedded Rust
- Branchless Rust: Making a Filter 4x Faster by Removing an
if - Why modern font metrics cannot reproduce Word pagination
- Building hooklog on a six-day-old framework
Crate of the Week
This week's crate is index_type, a crate for providing strongly typed indices for collections.
Thanks to Roee Shoshani for the self-suggestion!
Please submit your suggestions and votes for next week!
Calls for Testing
An important step for RFC implementation is for people to experiment with the implementation and give feedback, especially before stabilization.
If you are a feature implementer and would like your RFC to appear in this list, add a call-for-testing label to your RFC along with a comment providing testing instructions and/or guidance on which aspect(s) of the feature need testing.
No calls for testing were issued this week by Rust, Cargo, Rustup or Rust language RFCs.
Let us know if you would like your feature to be tracked as a part of this list.
Call for Participation; projects and speakers
CFP - Projects
Always wanted to contribute to open-source projects but did not know where to start? Every week we highlight some tasks from the Rust community for you to pick and get started!
Some of these tasks may also have mentors available, visit the task page for more information.
- Cordial - Unify the two implementations of the profile lock
- Cordial - Fullscreen clips and letterboxes until the workspace is switched away and back
- Dofigen - Extend Dockerfiles
If you are a Rust project owner and are looking for contributors, please submit tasks here or through a PR to TWiR or by reaching out on Bluesky or Mastodon!
CFP - Events
Are you a new or experienced speaker looking for a place to share something cool? This section highlights events that are being planned and are accepting submissions to join their event as a speaker.
If you are an event organizer hoping to expand the reach of your event, please submit a link to the website through a PR to TWiR or by reaching out on Bluesky or Mastodon!
Updates from the Rust Project
630 pull requests were merged in the last week
Compiler
- improve CFG traversal
- perf: avoid a heap allocation per basic block in MoveData's location maps
- stabilize passing 128-bit integers via vector registers with
asm!on x86
Library
- a bit optimize four-digit chunks in integer formatting
- add NEON support for
is_asciiandeq_ignore_ascii_case - add semver check test command for checking API compatibility of stdlib
- allow only implementing
Read::read_buf - core: implement bounded random sampling
- iter: specialize
Take::countusingadvance_by - iter: specialize
advance_bymethod ofFuse - make atomic operations const
- move
std::io::copytoalloc::io - stabilize
size_of_val_raw, align_of_val_raw, Layout::for_value_raw
Cargo
- add a suggestion when adding
[lints]to a workspace to use[workspace.lints]instead - avoid parsing unchanged lockfiles
- completions: complete paths for cargo run arguments
- fix
manual_readmelint for lower-priority README files - git: make checkout names independent of git config
- make
__CARGO_TEST_FORCE_ARGFILEavailable in distributed builds - pass rustdoc flags to final CCI merge step
- prevent panic when
package.buildis empty - reworked how we enable the new build-dir layout on nightly
- trim-paths: unambiguous and reversible remap rules
Rustdoc
- label badge for notable traits
- rustdoc-json: make
Stabilitycompatible with non-self-describing serde formats - fix ICE when a grapheme cluster joins a Prepend-class character to
_or: - fix crash when trying to list attributes on an opaque type
- only analyze head of self type when deciding impl inlining
Rustfmt
Clippy
manual_div_ceil: avoid suggestions that change evaluation count- fix
no_effect_underscore_bindingfalse positive on proc-macro generated code - add check for image with embedded link to
doc_paragraphs_missing_punctuation - lint for UFCS call in
clone_on_copy - trigger
float_cmp_constforassert_eq!with const floats
Rust-Analyzer
- allow
selfas the last segment of a path - correctly handle unlinked module edge cases
- support
CovariantUnsafeCell - add
-Zjson-target-specon cargo calls where needed - add reference for same name param coerce matches
- allow diverging rhs in destructuring assignments
- avoid panic when checking
Copyfor hrtb closure arguments - detect the rust-analyzer component in a multi-line components array
- do not alloc anon consts for bare paths in blocks
- don't panic on a self-referential
impl Traitfunction - double stack size for threads to 16MiB
- exclude unknown types from term search
- fix lookup
MACRO_CALL@...in this Semantics due to include! - fix
ExprScopeshandling of exprs inside patterns - fix glob import shadowing bug
- make mir debug execution work fot bitflags items
- mark auto traits as coinductive
- no hint with similar name raw-ident arg
- parse postfix range inside closure in access
- recognize format arguments after a backslash in raw strings
- resolve assignment lhs in its expression scope
- show qualified paths when type names collide in E0308
- hir-ty, ide-diagnostics: use E0057/E0061 for arg-count mismatch (was E0107)
- perf: avoid having a separate query for defined opaques
- perf: save an allocation in lifetime handling
- report a config error for postfix snippets with item scope
vfs: use component-based path prefix matching for virtual paths
Rust Compiler Performance Triage
A lot of optimizations landed this week. Some big improvements to rustdoc in #159854, one big improvement in control flow graph traversal for cranelift-codegen, few more improvements to next-solver benchmarks and various other micro-optimizations, bringing the total to a nice round number of 10 improvements this week.
Triage done by @panstromek. Revision range: ad0c9dce..65dd30fb
Summary:
| (instructions:u) | mean | range | count |
|---|---|---|---|
| Regressions ❌ (primary) |
0.3% | [0.2%, 0.5%] | 18 |
| Regressions ❌ (secondary) |
2.1% | [0.1%, 16.8%] | 64 |
| Improvements ✅ (primary) |
-3.3% | [-39.8%, -0.2%] | 97 |
| Improvements ✅ (secondary) |
-6.1% | [-39.6%, -0.1%] | 111 |
| All ❌✅ (primary) | -2.7% | [-39.8%, 0.5%] | 115 |
1 Regression, 5 Improvements, 11 Mixed; 6 of them in rollups 32 artifact comparisons made in total
Approved RFCs
Changes to Rust follow the Rust RFC (request for comments) process. These are the RFCs that were approved for implementation this week:
- No RFCs were approved this week.
Final Comment Period
Every week, the team announces the 'final comment period' for RFCs and key PRs which are reaching a decision. Express your opinions now.
Tracking Issues & PRs
- Tracking Issue for
core_io_borrowed_buf - Tracking Issue for
derive_macro_global_path - stabilize
c_variadic_naked_functions
- Implement a naming convention for lint/diagnostic-only
rustc_attrs - Encode OpenBSD
-currentversion in targets'target_env - Add
target_feature_available_at_call_site - Promote
wasm32-wasip3to Tier 2
No Items entered Final Comment Period this week for Rust RFCs,Language Reference, Cargo, Language Team, Leadership Council or Unsafe Code Guidelines. Let us know if you would like your PRs, Tracking Issues or RFCs to be tracked as a part of this list.
New and Updated RFCs
- No New or Updated RFCs were created this week.
Upcoming Events
Rusty Events between 2026-08-05 - 2026-09-02 🦀
Virtual
- 2026-08-05 | Virtual (Cardiff, UK) | Rust and C++ Cardiff
- 2026-08-05 | Virtual (Indianapolis, IN, US) | Indy Rust
- 2026-08-07 | Virtual (Girona, ES) | Rust Girona
- 2026-08-10 | Hybrid (Kuala Lumpur, Malaysia) | Rust Malaysia Meetup
- 2026-08-11 | Virtual (Dallas, TX, US) | Dallas Rust User Meetup
- 2026-08-13 | Virtual (Berlin, DE) | Rust Berlin
- 2026-08-13 | Virtual (Nürnberg, DE) | Rust Nuremberg
- 2026-08-14 | Virtual (Girona, ES) | Rust Girona
- 2026-08-18 | Virtual (Washington, DC, US) | Rust DC
- 2026-08-19 | Hybrid (Vancouver, BC, CA) | Vancouver Rust
- 2026-08-20 | Hybrid (Seattle, WA, US) | Seattle Rust User Group
- 2026-08-20 | Virtual (Charlottesville, VA, US) | Charlottesville Rust Meetup
- 2026-08-21 | Virtual (Girona, ES) | Rust Girona
- 2026-08-25 | Virtual (Dallas, TX, US) | Dallas Rust User Meetup
- 2026-08-27 | Virtual (Berlin, DE) | Rust Berlin
- 2026-08-21 | Virtual (Girona, ES) | Rust Girona
- 2026-09-02 | Virtual (Indianapolis, IN, US) | Indy Rust
Africa
- 2026-08-11 | Johannesburg, ZA | Johannesburg Rust Meetup
Asia
- 2026-08-10 | Hybrid (Kuala Lumpur, MY) | Rust Malaysia Meetup
- 2026-08-22 | Bangalore, IN | Rust Bangalore
- 2026-08-22 | Delhi, IN | Rust Delhi
- 2026-08-22 | Noida, IN | SciPy India
- 2026-08-29 | Pune, IN | Rust Pune
Europe
- 2026-08-05 | Köln, DE | Rust Cologne
- 2026-08-06 | Berlin, DE | Rust Berlin
- 2026-08-06 | Oxford, UK | Oxford ACCU/Rust Meetup.
- 2026-08-13 | Switzerland, CH | PostTenebrasLab
- 2026-08-18 | Aarhus, DK | Rust Aarhus
- 2026-08-18 | Leipzig, DE | Rust - Modern Systems Programming in Leipzig
- 2026-08-20 | Frankfurt, DE | Rust Rhein-Main
- 2026-08-27 | Manchester, GB | Rust Manchester
North America
- 2026-08-06 | Mountain View, CA, US | Hacker Dojo
- 2026-08-06 | Saint Louis, MO, US | STL Rust
- 2026-08-11 | New York, NY, US | Rust NYC
- 2026-08-13 | Lehi, UT, US | Utah Rust
- 2026-08-13 | San Diego, CA, US | San Diego Rust
- 2026-08-15 | San Francisco, CA, US | Flower
- 2026-08-18 | San Francisco, CA, US | San Francisco Rust Study Group
- 2026-08-19 | Hybrid (Vancouver, BC, CA) | Vancouver Rust
- 2026-08-19 | San Francisco, CA, US | Bay Area Rust
- 2026-08-20 | Hybrid (Seattle, WA, US) | Seattle Rust User Group
- 2026-08-26 | Austin, TX, US | Rust ATX
- 2026-08-26 | Los Angeles, CA, US | Rust Los Angeles
- 2026-08-27 | Atlanta, GA, US | Rust Atlanta
Oceania
- 2026-08-27 | Melbourne, AU | Rust Melbourne
South America
- 2026-08-08 | São Paulo, SP | Rust-SP
If you are running a Rust event please add it to the calendar to get it mentioned here. Please remember to add a link to the event too. Email the Rust Community Team for access.
Jobs
Please see the latest Who's Hiring thread on r/rust
Quote of the Week
… but I gave up on the idea as the macro rules were turning into a turing complete rust syntax parser
Thanks to miro for the suggestion!
Please submit quotes and vote for next week!
This Week in Rust is edited by:
- nellshamrell
- llogiq
- ericseppanen
- extrawurst
- U007D
- mariannegoldin
- bdillo
- opeolluwa
- bnchi
- KannanPalani57
- tzilist
Email list hosting is sponsored by The Rust Foundation
05 Aug 2026 4:00am GMT
04 Aug 2026
Planet Mozilla
The Rust Programming Language Blog: Enabling the next iteration of the borrow checker on nightly
TL;DR We are enabling the next iteration of the borrow checker (coined Polonius Alpha) on nightly in preparation for stabilization in the next few months.
Whaaaaaat?
Yes! You heard it right! The next iteration of the Rust borrow checker is coming! Rust's first borrow checker ("AST borrowck") was very limited and was phased out in 2019 in favor of NLL, other than a "migrate mode" that was used to provide nice error messages. That migrate mode was finally removed in 2022.
The Polonius borrow checker spun out of the NLL effort in 2018. The initial formulation passed the NLL test suite and accepted (sound) code that NLL did not. However, performance was a critically-limiting factor; generally borrow check was slower than NLL, but certain programs were considerably slower than NLL to the extent that using that implementation/formulation of Polonius was a non-starter. Attempts were made over the years to implement the Polonius formulation in a performant manner, without much luck in addressing the core issues.
In 2023, a new formulation of a Polonius-style borrow checker was imagined that required minimal rearchitecture of the existing NLL implementation and could be extended to allow more code to compile. We had hoped, to try to stabilize this new formulation in 2024; but, various things popped up that delayed this.
But! We're nearly there now! At this point, there are no known remaining issues with the subset coined Polonius Alpha that we intend to stabilize. And, performance is generally acceptable for stabilization (will discuss that a bit below).
So, we are enabling the Polonius Alpha borrow checker on nightly for testing until we stabilize fully later in the year. We're doing this in order to help find:
- Any serious performance regressions we're unaware of
- Unsoundness in the formulation that we haven't thought about
- Any weird diagnostic issues that we need to improve
- Note: we have not yet seen any diagnostic changes
You can report any issues on Github or on Zulip.
Okay, what's new?
The key thing that Polonius Alpha enables that NLL does not is flow-sensitive borrow checking of lifetime outlives relationships.
Perhaps the smallest example demonstrating what will pass with Polonius Alpha but not the current NLL is:
fn reborrow(a: &mut u8) -> &mut u8 {
let b = &mut *a;
if true { b } else { a }
}
However, the example you will see more often is:
fn get_mut_or_default<'r, K: Hash + Eq + Copy, V: Default>(
map: &'r mut HashMap<K, V>,
key: K,
) -> &'r mut V {
match map.get_mut(&key) {
Some(value) => value,
None => {
map.insert(key, V::default());
map.get_mut(&key).unwrap()
}
}
}
The issue is that the Some(value) => value branch causes the borrow checker to think that the borrow returned by map.get_mut(&key) lives for the entire function (because of the &'r mut V return type), even though that borrow isn't live in the None branch. NLL's analysis is flow-insensitive.
Polonius Alpha passes this because its analysis is flow-sensitive, and it knows that the borrow isn't live in the None branch.
Now, Polonius Alpha is not perfect; some programs that would compile under legacy Polonius (the slow original implementation) don't compile with Polonius Alpha. (This is of course why we call it "Polonius Alpha"). For example:
struct X { next: Option<Box<X>> }
fn conditional() {
let mut b = Some(Box::new(X { next: None }));
let mut p = &mut b;
while let Some(now) = p {
if true {
p = &mut now.next;
}
}
}
(As a slight note: we have also found programs that compile with Polonius Alpha but not legacy Polonius, so it's not really a full subset.)
So, what about performance?
Polonius Alpha currently does strictly equal or more work compared to NLL, so we have been paying particular attention to potential performance regressions.
From the top ten thousand crates by downloads on crates.io, we have seen relatively few "significant" regressions, and even crates that have a "significant" regression are typically relatively minimal:

Each point represents a crate within the 10,000 most-downloaded crates. The black line is an arbitrary threshold of significance, set to a 1% regression and quadratically scaled below 30 seconds. Red points are crates that pass this arbitrary regression threshold. X-axis is compile time (for the leaf crate only without dependencies) under NLL; Y-axis is the ratio of compile time under Polonius Time compared to NLL.
If you look at the top five crates, they are:

Outside the top ten thousand crates, we have focused mainly on crates with many borrows. The worst case we've seen is a 2-3x regression.
We have done some initial triage of the causes of these regressions and are thinking about the best way to fix them. Though, overall we think these regressions are fairly reasonable even if we can't fix them, given how rare and relatively minimal they are compared to the additional power Polonius Alpha brings over NLL.
I really don't want this. How do I opt-out?
To reiterate: this is only being enabled on nightly. But if you want to disable Polonius Alpha, and only use the stable NLL, you can pass -Zpolonius=off to rustc, use RUSTFLAGS=-Zpolonius=off, or with a project's .cargo/config.toml configuration file:
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Zpolonius=off"]
If you have to do this, for some reason, please do tell us why on Github or on Zulip.
What's next?
Over the next few months, we will be monitoring Github and Zulip for any reported issues about Polonius Alpha. We will also be working to address known performance regressions. Finally, we will be working on internal documentation about the implementation. All prior to stabilization. Then, we are aiming to stabilize prior to the end of the year!
Although some programs that we want to compile don't work with Polonius Alpha (nor NLL today), we don't currently have any concrete plans to continue active feature work on the Polonius implementation after the stabilization of Polonius Alpha. We expect to continue to optimize the implementation and address any performance regressions for a little while. We will likely come back to Polonius feature-work at some point, but given that Polonius Alpha solves the most-encountered borrow-check issues, we are shifting our time to other high-priority work for the near future.
04 Aug 2026 12:00am GMT