skip to content

React's reconciler keeps two fiber trees in memory at once, connected by an alternate pointer on each fiber. What are the two trees, and what does maintaining both buy React?

level: seniorimportance: nice to knowfreq 28%

answer

  1. one tree shown, one tree being built
  2. borrowed from graphics buffers
  3. each node has a twin it recycles
  4. the swap is a single pointer assignment
  5. half-finished work was never visible

basics

~20 s

React keeps the current tree, which matches what is on screen, and a work-in-progress tree it builds for the pending update; each fiber's alternate points at its counterpart in the other tree. The screen changes only when React swaps which tree is current, so unfinished work can be thrown away.

solid answer

~50 s

The two trees are `current` — the one whose state matches what the browser is showing — and the work-in-progress tree that React builds while processing an update. Each fiber holds an `alternate` pointer to its twin in the other tree, so instead of allocating a fresh node for every position on every update, React reuses the twin and overwrites its fields. When the update is finished and applied, React flips the root's pointer to the tree it just built; the old `current` becomes the spare that the next update will write into. This is double buffering, borrowed from graphics: you draw the next frame off-screen and swap. Two things fall out of it. Work that is never finished costs nothing to abandon, because nothing was shown from it. And React always has the previous props and state available beside the new ones, since the twin still holds them.

go deeper

for a junior

Recall the shape of it: React has one tree describing what is on screen and builds a second one for the pending update, then switches which is live.

for a middle

Explain the recycling — each fiber's alternate is its counterpart in the other tree, so React overwrites an existing object per position instead of allocating a new tree per update.

for a senior

Connect it to guarantees you rely on in production: the DOM is untouched until the swap, so an abandoned or superseded render is invisible, and a failure during rendering leaves the committed tree intact.

for a principal

Own the general principle. Building a new version off to the side and publishing it with one atomic pointer swap is the standard way to get consistent reads under concurrent writes, and you should be able to name where else your architecture does or should apply it.

## Two trees, one screen At any moment React has two fiber trees. The **current** tree describes what the user is looking at: its fibers hold the props and state that produced the DOM as it currently exists. The **work-in-progress** tree is the one React builds while it processes an update — the version of the UI it is trying to make true. The root object holds a pointer named `current` that says which of the two is the live one. That pointer is the whole trick: the screen is defined by which tree `current` names, not by which tree React most recently touched. ## The alternate link Building a whole new tree of nodes for every keystroke would be wasteful, so the two trees are not independent allocations. Each fiber carries an `alternate` pointer to its counterpart at the same position in the other tree. When React needs a work-in-progress fiber for a position, it takes the existing fiber's `alternate` and overwrites the fields it needs — incoming props, updated state, work flags — rather than allocating. After the first update, the pair of objects at each position is allocated once and recycled back and forth forever. The relationship is symmetric: if A's `alternate` is B, then B's `alternate` is A. Which of the pair is "current" changes each time React commits. ## The swap When React has finished building the work-in-progress tree and has applied its changes to the DOM, it assigns the root's `current` pointer to the tree it just built. That single assignment is what makes the new version official. The tree that was current becomes the spare, and the next update will write into it. This is exactly double buffering from computer graphics: draw the next frame into an off-screen buffer, then flip which buffer is displayed, so the user never sees a partially drawn frame. ## What the design buys **Abandoning work is free.** Because nothing built into the work-in-progress tree affects the screen until the swap, React can stop halfway through building it, throw the partial work away, and start again with newer input. The user cannot have seen anything inconsistent, because the DOM was never touched. Any architecture where a render can be restarted or superseded needs this property; without it, half-applied updates would be visible. **Allocation stays bounded.** Recycling the alternate keeps the number of fiber objects proportional to the size of the UI rather than to the number of updates. Only newly mounted positions allocate. **The previous version is always at hand.** Standing at a work-in-progress fiber, React can follow `alternate` to the committed one and read the props and state that are currently on screen. That is how it can compare old against new, and how it knows which DOM attributes actually need writing. **Errors have somewhere to fall back to.** If building the next tree fails, the committed tree is still intact and still current — it was never mutated in place. ## What this does not mean Two trees does not mean two copies of the DOM. Real DOM nodes are singular and shared: both fibers of a pair point at the same node, because there is only ever one node on the page for that position. The duplication is only in React's bookkeeping. It also does not mean React holds a full history. There are exactly two versions — the committed one and the one being built. Nothing older is retained, so this is not an undo mechanism and cannot be used as one. ## Naming it safely `alternate` and the root's `current` pointer are real names in React's reconciler, and using them shows you have looked inside. They are internals, not API: there is no supported way to reach them from application code, and depending on them would break across releases. The observable contract is the one React documents — that an update is applied as a unit and that the DOM never shows a half-finished render. ## The compressed answer "React double-buffers its fiber tree: a current tree matching the screen and a work-in-progress tree it builds for the update, with each fiber's `alternate` pointing at its twin so the objects are recycled rather than reallocated. Applying an update is a pointer flip on the root, which means unfinished work can be dropped without the user ever seeing it."

  • If there are two fiber trees, are there also two sets of DOM nodes?
    No. A position has exactly one real DOM node, and both fibers of an alternate pair reference the same one. The duplication exists only in React's own bookkeeping so it can hold the committed version and the pending version side by side; the document is never duplicated, which is also why the swap costs nothing in the browser.
  • Does the alternate pointer mean React can undo an update?
    No — only two versions exist at any time, the committed tree and the one being built. Once React swaps, the previous tree becomes the scratch space for the next update and its old field values are overwritten. There is no retained history, so undo has to be implemented in application state, not expected from the reconciler.
  • Why is the previous props value still reachable while React builds the new tree?
    Because the twin fiber has not been touched. Following `alternate` from a work-in-progress fiber lands on the committed fiber, which still holds the props and state that produced what is on screen. That side-by-side availability is what lets React determine which DOM attributes genuinely differ instead of rewriting every one of them.

It is the same trick as double buffering in graphics: you paint the next frame into an off-screen buffer and then flip which buffer the display reads, so nobody ever sees a half-drawn frame — and if you abandon the drawing, nothing on screen changes.

saying these in an interview costs you the question

  • Thinking React keeps two copies of the actual DOM
  • Saying the alternate pointer enables undo or time travel
  • Believing React allocates a whole new fiber tree per update
  • Assuming the screen updates progressively as the new tree is built
  • Describing the two trees as parent and child rather than twins

context