awesome-everything RU
↑ Back to the climb

Browser & Frontend Runtime

The fiber object and the double-buffer tree

Crux A fiber is a plain JS object — one per component — holding state, hooks, and tree pointers. The linked-list structure is what makes rendering interruptible, and the two-tree double buffer is what makes interruption free.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 12 min

React cannot pause a recursive function — the call stack is a system resource it does not own. The fiber architecture solved this by replacing the call stack with a data structure React controls: a linked tree of objects it can stop and resume at any node.

What a fiber actually is. A fiber is a plain JavaScript object — one per component instance, one per DOM element in the tree. Each fiber holds: the component type, its props, its key, its current state and hooks, pointers to its child, its next sibling, and its return (parent), plus an alternate pointer to its counterpart in the other tree. The fibers form a linked tree, not an array — and that linked structure is the whole point.

A recursive tree walk lives on the call stack and cannot be paused; a linked-list walk holds its position in a plain variable, so React can stop after any fiber, store the pointer, and resume from exactly there later. Fiber is the data structure that made interruptible rendering possible. The name predates React 18 — the architecture landed in React 16 (2017) — but only React 18 turned on the concurrent features that exploit it.

Fiber object fields
FieldWhat it holds
typeThe component function or DOM tag
propsCurrent props passed to this node
keyThe reconciliation key
memoizedStateLinked list of hook records (useState, useEffect …)
child / sibling / returnTree navigation pointers (not a call stack)
alternatePointer to the twin fiber in the other tree

The two trees: current and workInProgress. React always holds two fiber trees. The current tree is the one whose state matches what is painted on screen right now. When an update starts, React builds a workInProgress tree — cloning fibers from current as it goes, applying new props and state. Each fiber’s alternate pointer links it to its twin in the other tree, so cloning is cheap: unchanged subtrees can be reused by reference.

When the workInProgress tree is complete and committed, the two trees swap: workInProgress becomes current, and the old current tree is kept around to become the next workInProgress. This is double buffering. It guarantees the on-screen tree is never observed in a half-updated state — and it is why a render that gets interrupted and thrown away costs nothing permanent: the discarded workInProgress tree simply never commits.

Why this works

Why fiber, not recursion? Before React 16, reconciliation was an ordinary recursive function. Recursion lives in the JS engine’s call stack, which cannot be paused and resumed — a function either runs to completion or does not run at all. This meant the entire render for a large tree was one indivisible synchronous task. Fiber replaced the recursion with an explicit linked-list walk: the “call stack” became a data structure in the heap that React owns and can stop, save, and resume. The name refers to the “fiber” concept from systems programming — a user-space lightweight thread — because a fiber tree is essentially a hand-implemented suspendable call stack on top of plain JS.

Quiz

Why is reconciliation with a linked fiber tree interruptible, while a recursive approach is not?

Quiz

A render is halfway done when a higher-priority update arrives. React throws away the in-progress workInProgress tree and starts over. Why does this cost nothing permanent?

Order the steps

Order the steps of one React render cycle, from state change to tree swap.

  1. 1 Update arrives — React schedules work on the appropriate lane
  2. 2 Fiber walk begins — clone fibers from current into workInProgress
  3. 3 Run component functions, reconcile new element tree
  4. 4 Commit: apply DOM mutations from workInProgress
  5. 5 Swap: workInProgress becomes current; old current kept for next cycle
Recall before you leave
  1. 01
    What fields on a fiber object enable the linked-tree walk?
  2. 02
    What does the alternate pointer on a fiber point to?
  3. 03
    Why can a discarded workInProgress tree be thrown away at zero visible cost?
Recap

A fiber is a plain JS object holding a component’s type, props, key, state, and hooks, plus child/sibling/return pointers that form a linked tree. Unlike a recursive call stack, this linked tree can be stopped after any node by saving a cursor variable, which is the structural basis for interruptible rendering. React always keeps two of these trees: the current tree (matching the screen) and the workInProgress tree (the update being built). The alternate pointer on each fiber links it to its twin across the two trees, making cloning cheap. When a render commits, the trees swap; when a render is abandoned, the workInProgress tree is discarded at zero cost because it never touched the DOM.

Connected lessons
appears again in143
Continue the climb ↑Render phase purity and commit phase sub-steps
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.