React tracks the work pending on a root as "lanes" — bits in a bitmask — rather than as a single current priority number. What does that representation let React do that one number could not?
answer
- several updates pending at the same time
- a set, not a single value
- bitwise selection, union, subtraction
- identity as well as rank
- skipped work still needs a deadline
basics
~20 sA bitmask records a whole set of pending priorities at once, so React can render a chosen subset in one pass, keep the rest marked as still pending, and tell otherwise-similar updates apart — all with cheap bitwise set operations.
solid answer
~50 sA root usually has several updates pending at different priorities simultaneously, so a single number cannot describe its state — it can say what React is working on but not what is still waiting. A bitmask represents the whole set: React can test, union and subtract lanes with single bitwise operations, select a batch of lanes to render together, and leave the unselected bits set so that after the commit it knows exactly what still needs scheduling. Separate bits also let React distinguish two transitions that are pending at the same time, which matters when one suspends and later resolves and React has to know which pending work that unblocks. And because the set is explicit, React can give a lane that keeps being skipped a deadline and eventually render it synchronously, so low-priority work cannot be starved forever. It is all internal, unstable, and not something you code against.
go deeper
It is enough to know that several updates with different urgencies can be waiting at once and React keeps track of all of them, rather than only the one it is rendering.
Explain why a set is required rather than a scalar: React renders a selected batch and must remember exactly what was left pending for the next scheduling pass.
Show the consequences you can reason from — batch selection, identity for suspended-and-resumed work, and a deadline mechanism that keeps skipped lanes from starving — while flagging that all of it is internal.
Judge how much internal detail belongs in your team's mental model, and insist that application code express intent through the public priority APIs rather than any assumption about scheduler internals.
## The problem a single number cannot express Imagine a root with three things outstanding: a keystroke's urgent update, a transition started by a route change, and a second transition from a filter panel. A single "current priority" field can answer *what am I rendering now*. It cannot answer *what else is waiting*, *did the thing I just rendered include that other update*, or *which pending work does this resolved promise unblock*. React needs all three answers on every commit, so the state it keeps has to be a set, not a scalar. A bitmask is the cheapest possible set over a small fixed universe. Each kind of work gets a bit — one for synchronous work, one for updates from continuous input, a default one, a block of bits for transitions, ones for retries after suspending, an idle one — and the root holds a word of pending bits. ## What the representation buys, concretely **Set arithmetic in one instruction.** "Does this render include that update?" is an AND. "Mark these lanes as done" is a subtraction. "Add this update to the pending set" is an OR. "Which is the highest pending?" is isolating the lowest set bit. These run on every scheduling decision, so making them constant-time and allocation-free matters. **Rendering a batch, not a single update.** React selects a group of lanes to render in one pass. Everything selected is included in the same work-in-progress tree; everything not selected keeps its bit set and is re-scheduled after the commit. With a scalar you would have to render strictly one priority level at a time or lose track of the remainder. **Telling similar work apart.** Two transitions started at nearly the same moment are equal in urgency but are not the same work. Giving them distinct bits lets React answer questions that depend on identity, not just rank — most importantly, when a component suspends during one transition and its promise later resolves, React needs to know which pending lanes that unblocks and re-render exactly those. **Expressing relationships between lanes.** Some updates must not be split apart — for example, when React has to guarantee that certain updates are processed together for consistency, it can mark those lanes as tied to each other so that selecting one selects the others. That is a statement about a *set* and has no scalar equivalent. **Starvation control.** Lower-priority lanes are skipped whenever higher ones are pending. If typing never stops, a transition could in principle wait forever. Because the pending set is explicit and durable, React can attach a deadline to each waiting lane and, once it is exceeded, treat that lane as expired and render it synchronously — trading responsiveness for the guarantee that queued work eventually lands. ## What to actually say in an interview Almost no interviewer wants lane constant names, and offering them is usually a sign of having memorised a blog post. The answer that lands is the shape of the problem: *multiple updates with different urgencies are pending at once, so React needs a set; a bitmask makes set operations free and lets React render a chosen batch while remembering the rest; distinct bits also give otherwise-equal work an identity, which suspended-and-resumed renders depend on; and an explicit pending set is what makes starvation avoidable.* ## The caveat that should come with it Lanes are internal implementation. They are not exported, not stable across versions, and nothing in application code should branch on them. The knowledge is useful for reasoning about *why* two updates can coexist at different priorities and why a low-priority update eventually lands even under constant input — not for writing code. Saying that out loud is part of a good answer, because it shows you know where the public contract ends.
- Why does React need to tell two same-priority transitions apart at all?Because suspending makes identity matter. If a component suspends during one transition and the promise resolves later, React must re-render the work that was blocked — not whatever else happens to be pending at the same rank. Distinct bits let React record which pending work a given resolution unblocks, which a shared priority number could not express.
- How does React stop a low-priority update from being starved by constant urgent work?Because the pending set is explicit and durable, React can give a waiting lane a deadline. Once that deadline passes, the lane is treated as expired and rendered synchronously rather than being skipped again. It gives up interruptibility for that update in exchange for a guarantee that queued work eventually commits.
- Should application code ever branch on lanes?No. Lanes are unexported internals whose layout has changed between versions, and nothing in the public API surfaces them. The useful public expressions of priority are transitions, deferred values and `flushSync`. Reasoning about lanes helps you predict behaviour; depending on them produces code that breaks on a React upgrade.
saying these in an interview costs you the question
- Says lanes are part of React's public API
- Thinks a root can only have one pending priority at a time
- Claims a bitmask is only a micro-optimisation over a number
- Assumes low-priority work can be starved indefinitely