3.2 Lanes: priority as bits in a number
In the last lesson you saw why React ranks updates: a keystroke must beat a slow background re-render. This lesson answers the next question — how does React actually store a priority? The surprising answer: a priority is a single bit inside one ordinary 32-bit number, and React reads, combines, and tests those priorities with nothing more than bitwise math.
A lane is a single bit
A lane is literally one bit in a 32-bit number. React uses 31 usable bits (positions 0–30). Different kinds of updates light up different bits, and each lane has a name.
Here is the real layout, with the actual lane constants React defines.
The real code
// 32-bit layout (bits 0–30 usable, bit 31 reserved):
//
// Bit 31 (reserved)
// │ Bit 30 (DeferredLane)
// │ │ Bits 27–29 (Idle/Offscreen)
// │ │ │ Bits 7–26 (Transition/Retry/Selective)
// │ │ │ │ Bits 0–6 (Sync/Input/Default)
// ▼ ▼ ▼ ▼ ▼
// [X][D][III][TTTTTTTTTTTTTTTTTTT][SSSSSSS]
SyncLane = 0b0000000000000000000000000000001; // bit 0 — most urgent
InputContinuousLane = 0b0000000000000000000000000000100; // bit 2 — dragging, scrolling
DefaultLane = 0b0000000000000000000000000010000; // bit 4 — normal setState
TransitionLane1 = 0b0000000000000000000000001000000; // bit 6 — startTransition work
IdleLane = 0b0100000000000000000000000000000; // bit 29 — least urgent
OffscreenLane = 0b1000000000000000000000000000000; // bit 30 — hidden/Activity content
Notice each constant has exactly one 1 in it — every lane is a distinct power of two. SyncLane is bit 0, DefaultLane is bit 4, TransitionLane1 is bit 6. Because no two lanes share a bit position, they never collide, and many of them can live in the same number at once.
The bit's position is the priority
The numbers are not arbitrary. The lower the bit position, the more urgent the work. Bit 0 (SyncLane) is the most urgent — a click or keypress. Bit 30 (OffscreenLane) is the least urgent — hidden content. So the identity of an update and its priority are the same fact: which bit is set.
less urgent ◄────────────────────────────────► more urgent bit 30 bit 29 ... bit 6 bit 4 bit 2 bit 0 Offscreen Idle TransitionLane1 Default Input Sync
This is why a later lesson can "pick the most urgent work" so cheaply: the most urgent pending lane is just the lowest set bit of the number.
One number, many priorities: OR (|)
What if the same component has two updates waiting — say a transition that is still rendering, and then the user types? React does not grow an array. It flips on a second switch by combining the two bits with bitwise OR (|).
The real code
// T=0 ms: transition starts
fiber.lanes |= 0b1000000; // TransitionLane1 (64)
// fiber.lanes = 0b1000000 (64)
// T=5 ms: user types while transition is rendering
fiber.lanes |= 0b0000001; // SyncLane (1)
// fiber.lanes = 0b1000001 (65)
// ↑ ↑
// | └─ bit 0 = SyncLane
// └─────── bit 6 = TransitionLane1
// ONE number holds BOTH priorities
OR keeps every bit that was already on and turns on the new one. The result, 0b1000001, is a single integer that means "there is sync work and transition work here".
Bit position: 6543210
TransitionLane: 1000000 (64)
SyncLane: 0000001 (1)
OR result: 1000001 (65)
↑ ↑
Both bits set simultaneously
Asking "is this lane here?": AND (&)
Now React needs the opposite: given a number that may hold several lanes, does it contain a particular lane? That is a bitwise AND (&). AND keeps only the bits that are on in both numbers — so if any shared bit survives, the lane is present.
Checking SyncLane: fiber.lanes: 1000001 renderLanes: 0000001 AND result: 0000001 (non-zero → SyncLane IS present) Checking TransitionLane: fiber.lanes: 1000001 renderLanes: 1000000 AND result: 1000000 (non-zero → TransitionLane IS present)
The rule is simple: if a & b is non-zero, the two share at least one lane; if it is zero, they have no priority in common.
SEE IT IN THE SOURCE
React wraps that exact AND test in a tiny helper called includesSomeLane. This is the real function, and the worked numbers beside it.
// From ReactFiberLane.js
function includesSomeLane(a, b) {
return (a & b) !== NoLanes; // NoLanes = 0
}
// fiber.lanes = 0b1000001 (has both TransitionLane and SyncLane)
// Render pass is processing SyncLane only:
const renderLanes = 0b0000001;
includesSomeLane(0b1000001, 0b0000001)
// = (0b1000001 & 0b0000001) !== 0
// = 0b0000001 !== 0
// = true ✅ fiber has SyncLane work
And the merge side — turning on a lane with OR — is the real function React calls every time setState records a new update. Open it to see the full version.
Show the full source — merging (|=) and clearing (&= ~) lanes
The real code — adding a lane with OR
function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {
// Add lane to the fiber that owns the update
sourceFiber.lanes |= lane;
let alternate = sourceFiber.alternate;
if (alternate !== null) {
alternate.lanes |= lane; // also mark the work-in-progress twin
}
// Walk to root, propagating childLanes upward
let parent = sourceFiber.return;
while (parent !== null) {
parent.childLanes |= lane;
if (parent.alternate !== null) {
parent.alternate.childLanes |= lane;
}
parent = parent.return;
}
}
The |= lines are the merge you just learned. (The walk toward the root — marking each ancestor's childLanes — is how React later skips whole subtrees; that mechanism belongs to lesson 3.3.)
The real code — the same AND test inside beginWork
// Inside beginWork:
function checkScheduledUpdateOrContext(current, renderLanes) {
return includesSomeLane(current.lanes, renderLanes);
// (current.lanes & renderLanes) !== 0
}
// If false → attemptEarlyBailoutIfNoScheduledUpdate()
// = skip this fiber (and walk childLanes to check subtree)
The real code — removing a finished lane with AND + NOT
// After rendering SyncLane, remove it:
const syncLane = 0b0000001;
fiber.lanes &= ~syncLane;
// Step 1: ~syncLane = 0b1111110 (all bits flipped)
// Step 2: 0b1000001 & 0b1111110 = 0b1000000
// Result: only TransitionLane1 remains
Once a render finishes, React clears that lane's bit with &= ~lane — AND with the inverted lane turns off just that one switch and leaves the rest untouched.