7 min read
0%

React Fiber Architecture

Back to Blog
React Fiber Architecture

React Fiber Architecture

Fiber is React’s internal reconciler, rewritten from scratch in React 16. It replaced the original stack-based reconciler with an architecture that makes rendering interruptible, prioritizable, and resumable.

Why Fiber Was Needed

The original reconciler used the JavaScript call stack for traversal. Once it started reconciling a component tree, it couldn’t stop until the whole tree was processed. On large trees, this blocked the main thread for tens of milliseconds — enough to drop frames and feel janky.

Fiber moves the tree traversal into a heap-allocated linked list that React controls. This lets React:

  • Pause work after processing each fiber unit
  • Resume from where it left off
  • Throw away in-progress work if higher-priority updates arrive
  • Reuse completed work

The Fiber Node

Each React element gets a corresponding fiber node:

{
  type,           // 'div' | MyComponent | etc.
  key,
  stateNode,      // DOM node for host elements, instance for class components
  return,         // parent fiber
  child,          // first child
  sibling,        // next sibling (forms a linked list)
  pendingProps,
  memoizedProps,
  memoizedState,  // hook state linked list (head node)
  updateQueue,    // pending state updates
  flags,          // side effect bitmask
  lanes,          // priority bitmask
  alternate,      // pointer to the other tree
}

The tree is structured as a child + sibling linked list, not an array of children. This lets React traverse it iteratively with a while loop and a pointer — no call stack growth.

Two Trees: Current and Work-in-Progress

React maintains two fiber trees simultaneously:

current tree          work-in-progress tree
(what's on screen)    (being built)

RootFiber ────────── RootFiber (alternate)
    │                     │
  App ──────────────── App (alternate)
    │                     │
  Header               Header (alternate)

Each fiber’s alternate points to its counterpart in the other tree. When a render completes, React swaps which tree is “current” by updating a single pointer at the root. This double-buffering pattern means the current tree is never mutated mid-render.

Work Loop

React’s work loop processes one fiber at a time:

function workLoop(deadline) {
  while (nextUnitOfWork && !shouldYield(deadline)) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
  }
}

shouldYield checks if the frame deadline is approaching (via scheduler package, which uses MessageChannel for sub-millisecond granularity). If yes, React yields and schedules the next chunk via postMessage.

Render Phase vs Commit Phase

Render phase (interruptible):

  • Calls component functions / render methods
  • Computes new fiber tree
  • Marks fibers with effect flags (Placement, Update, Deletion)
  • Can be paused and restarted — must be side-effect-free

Commit phase (synchronous, cannot be interrupted):

  • Walks the effect list
  • Mutates the DOM
  • Runs useLayoutEffect cleanup + setup
  • Schedules useEffect cleanup + setup via microtask/scheduler

Priority and Lanes

Fiber introduced a priority system called “lanes”. Each update is tagged with a lane:

const SyncLane         = 0b0001;  // user input, onClick
const InputContinuousLane = 0b0100;  // drag, scroll
const DefaultLane      = 0b1000;  // fetch, setTimeout
const TransitionLane   = 0b10000; // startTransition

React processes higher-priority lanes first. A startTransition update (low priority) gets paused if a click handler fires.

Practical Impact

  • Concurrent Mode: possible only because of Fiber’s interruptible render phase
  • Suspense: works by throwing a Promise — Fiber catches it, renders a fallback, retries when resolved
  • useEffect timing: effects are deferred to after paint because Fiber separates render from commit
  • StrictMode double-invocation: Fiber renders the work-in-progress tree twice in dev to catch impure render functions

Canvas is not supported in your browser