skip to content

Fiber Tree and Virtual DOM

The fiber tree is React's internal representation of your UI — one fiber per element, holding its state, effect flags, and links to child, sibling, and parent. Interviewers ask about it to see whether 'virtual DOM' means something concrete to you rather than being a slogan.

part ofReactoverview, primer and where to startread it →
on this pageshow

explore

questions

4

React is usually described as using a "virtual DOM". Concretely, what is that virtual DOM made of, and is updating it faster than updating the real DOM directly?

level: juniorimportance: must knowfreq 80%

answer

  1. plain objects, not DOM nodes
  2. description now, browser nodes later
  3. the framework performs the real writes
  4. cheap to allocate, cheap to discard
  5. maintainability, not raw speed

basics

~20 s

React's virtual DOM is a tree of plain JavaScript objects describing the intended UI. They are cheap to create, so React can compare them and write only the DOM that changed — not faster than optimal manual DOM work, just easier.

solid answer

~50 s

The virtual DOM is not a copy of the browser's DOM and it is not the Shadow DOM. It is a tree of ordinary JavaScript objects — React elements — each carrying a `type`, a `props` object and an optional `key`. Rendering a component just returns that description; React then compares it with the description it kept for the same position and applies the resulting changes to the real DOM itself. Behind those disposable elements React keeps a persistent tree of fiber nodes, which is where state and the DOM handles actually live. On speed I would be honest: every update React performs is a real DOM update, plus the extra work of allocating and comparing objects, so hand-tuned imperative code can always win a microbenchmark. What React buys is a declarative model with predictable, batched updates that stays fast enough as an app grows.

code

javascript · 7 lines
javascript
import { createElement } from 'react';

const element = createElement('button', { className: 'primary' }, 'Save');

console.log(element.type);           // 'button'
console.log(element.props.children); // 'Save'
console.log(typeof element.appendChild); // 'undefined' — not a DOM node

go deeper

for a junior

Be ready to say plainly that React elements are ordinary JavaScript objects, not DOM nodes, and that React is the one that writes to the browser based on them.

for a middle

Explain the cycle end to end: a render produces a fresh description, React compares it with the previous one for those positions, and only differing nodes and attributes are written to the document.

for a senior

Show you know the honest tradeoff. Point out that the diff itself costs allocation and traversal, that the usual cause of a sluggish React screen is rendering too many things, and that you would measure before assuming the framework is the bottleneck.

for a principal

Own the framing for the team: this is a programming-model choice — declarative UI with batched, predictable updates — and you should be able to compare it against approaches that update the DOM without a diff step, and say what each costs in ergonomics and runtime.

## The name is a metaphor; the thing is an object tree "Virtual DOM" is a marketing-friendly name for something quite plain. In React you never create or mutate browser nodes yourself. A component returns a *description* of what the UI should look like for the current props and state, and React owns the job of turning that description into browser nodes. A description node — a React element — is an ordinary JavaScript object. Roughly: ```javascript { type: 'button', // a tag name, or a component function key: null, // identity hint among siblings props: { className: 'primary', children: 'Save' }, } ``` It also carries a `$$typeof` symbol so React can recognise a genuine element (and so a JSON payload from a server cannot masquerade as one). There is no `appendChild`, no `style`, no layout — nothing browser-ish about it. Creating one costs about as much as creating any small object, which is the whole point: descriptions are cheap enough to throw away and rebuild constantly. ## What React does with the description Each time a component renders, it produces a fresh element tree. React compares that tree against the tree it kept from the previous render for the same positions, works out which real nodes and attributes actually differ, and applies those changes to the document in one pass. You express *what the UI should be for this state*; React decides *which DOM writes happen*. That inversion is the real product. Imperative UI code has to answer "given that this one thing changed, which of my twelve DOM nodes need editing?" — a question that gets harder with every feature. Declarative UI code answers "what does the screen look like now?", which stays the same difficulty forever. ## The disposable tree and the persistent tree A subtlety worth saying out loud: modern React has two internal trees, not one. The element tree is disposable — it is recreated on every render and becomes garbage immediately. Behind it React maintains a tree of **fiber** nodes, one per position in the UI, and those persist across renders. A fiber holds the component's state, flags describing the work to be done for it, and the handle to the real DOM node when there is one. So "virtual DOM" loosely names both: the throwaway descriptions your components return, and the long-lived internal tree React keeps them matched against. ## The performance myth Candidates lose points by claiming the virtual DOM is faster than the DOM. It is not, and it cannot be, for two reasons. First, every DOM update React makes *is* a DOM update. React does not have a private, cheaper channel into the browser; it calls the same APIs you would. It can only ever do the same work plus overhead. Second, that overhead is real: allocating an object per element on every render, walking two trees to compare them, and maintaining the fiber structure. Code written by a human who knows that only one text node can possibly change will beat React on that specific update, every time. What React does reliably avoid is the *pathological* case: a large app where updates are scattered, hand-written code does redundant reads and writes, and interleaved reads force the browser to recompute layout repeatedly. React collects changes and applies them together, which keeps the expensive parts of the browser's work — layout and paint — from being triggered more often than necessary. The honest framing is: not faster than optimal manual code, much faster than the manual code most teams actually write, and far easier to keep correct. ## What it costs, and when that matters The cost model is worth carrying in your head. Rendering a component allocates elements proportional to what it returns; rendering a list of 5,000 rows allocates thousands of objects and asks React to compare thousands of positions — even if nothing on screen changed. That is why very large rendered trees, not "the DOM being slow", are the usual source of React sluggishness, and why the fixes are about rendering fewer things rather than about making the diff cleverer. ## Answering it in an interview A strong two-sentence version: "The virtual DOM is a tree of plain objects describing the UI; React compares successive descriptions and applies the difference to the real DOM. It isn't faster than direct DOM manipulation — it's a programming model that makes correct, batched updates the default." Then, if asked to go deeper, mention that the persistent side of it is the fiber tree, not the element objects.

  • Is React's virtual DOM the same thing as the browser's Shadow DOM?
    No — they are unrelated despite the similar name. Shadow DOM is a browser standard for encapsulating a subtree and its styles inside a custom element. React's virtual DOM is an in-memory tree of plain JavaScript objects that only React knows about; it has no browser semantics, no style scoping, and never appears in the document.
  • If the virtual DOM adds overhead, why not have components write to the DOM directly?
    Because the moment two features can both touch the same node, you have to reason about every ordering of edits by hand. The description model makes each render a pure function of state, so the current screen is always derivable from data, and React can batch and reorder the actual writes. You trade a little CPU for a large drop in the class of bugs where the DOM and your data disagree.
  • Does React rebuild the whole DOM subtree when a component re-renders?
    No. A re-render rebuilds the element *descriptions* for that subtree, which are cheap objects. React then compares them with what it already has and touches only the real nodes and attributes that differ. Re-rendering is not the same as recreating DOM nodes, which is why a component can re-render often without visible cost.

saying these in an interview costs you the question

  • Claiming the virtual DOM is always faster than the real DOM
  • Describing it as an in-memory copy of the actual DOM tree
  • Confusing the virtual DOM with the browser's Shadow DOM
  • Saying a re-render recreates the component's DOM nodes
  • Believing React bypasses normal browser DOM APIs

context

open as a page

React keeps two kinds of internal objects for your UI: React elements and fiber nodes. What is each one, and which of them survives from one render to the next?

level: middleimportance: must knowfreq 52%

basics

~20 s

A React element is a throwaway plain object describing what you want at a position: type, props, key. A fiber is React's long-lived internal node for that position, holding state, work flags and the DOM handle. Elements are recreated each render; fibers persist.

open as a page

In React, a function component's body runs again from scratch on every render, yet the value returned by useState is still there. Where does React actually keep that state, and what follows from that when the same component is rendered in two places?

level: middleimportance: should knowfreq 45%

basics

~20 s

React stores hook state on the fiber node representing that component instance, as a chain of hook records matched by call order. Every rendered position has its own fiber, so two instances of the same component keep entirely separate state.

open as a page

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%

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.

open as a page