What Is Reconciliation in React? The Fiber-Powered Diffing Algorithm Explained

Reconciliation in React is the core algorithm that compares new virtual DOM trees against previous ones to compute the minimal set of changes needed to update the UI efficiently.

Reconciliation powers React's declarative programming model by ensuring the browser DOM stays synchronized with your component tree. When state or props change in the facebook/react repository architecture, this process determines exactly which nodes to create, update, or destroy without unnecessary re-rendering.

How Reconciliation Works in React

When a component calls setState, invokes a useState setter, or receives new props, React initiates a three-phase process defined in packages/react-reconciler/src/ReactFiberReconciler.js:

  1. Create a new virtual DOM tree – React generates a lightweight JavaScript object representation of the proposed UI state.
  2. Diff against the previous tree – The algorithm compares the new tree with the current Fiber tree to detect insertions, deletions, and prop updates.
  3. Generate minimal mutations – React produces the smallest possible set of DOM operations and hands them to the renderer for the commit phase.

The Three Key Invariants of the Diffing Algorithm

The reconciliation algorithm in packages/react-reconciler/src/ReactFiberWorkLoop.js operates under strict invariants that enable O(n) complexity:

  • Elements of the same type share the same component class or function – When React encounters identical element types, it reuses the existing instance and updates only props and state rather than destroying and recreating the component.

  • Elements with a key prop are matched by key within the same list – The key attribute provides stable identity for items that move, insert, or delete, allowing the reconciler to preserve component state during reordering.

  • Children are processed depth-first – The algorithm guarantees parent changes reconcile before their children, preserving the correct order of side-effects and ensuring the tree structure remains consistent.

Inside the React Reconciler: Fiber Architecture

The modern reconciliation engine centers on Fiber, a reimplementation of React's core algorithm introduced to enable incremental rendering and concurrency.

Fiber Nodes and the Tree Structure

In packages/react-reconciler/src/ReactInternalTypes.js, Fiber nodes are defined as the internal units of work. Each Fiber represents a component instance, its current state, and pointers to its parent, siblings, and children. The Fiber tree is a mutable linked structure that React traverses during reconciliation.

The Render Phase (Begin Work)

The render phase, implemented in packages/react-reconciler/src/ReactFiberBeginWork.js, walks the Fiber tree and compares current fibers with new elements. This "begin work" phase decides whether to:

  • Update an existing fiber by reusing it with new props
  • Delete a fiber by marking it for removal
  • Create a new fiber for new elements

This phase is pure and side-effect-free, allowing React to pause or restart work for higher-priority updates.

The Commit Phase

Once React calculates all necessary changes, the commit phase in packages/react-reconciler/src/ReactFiberCommitWork.js applies side-effects synchronously. This includes performing DOM mutations, calling lifecycle methods, and updating refs. The commit phase cannot be interrupted to ensure UI consistency.

Practical Examples of Reconciliation in Action

State Updates and Virtual DOM Diffing

When setState triggers reconciliation, React creates a new element tree and diffs it against the previous render:

function Counter() {
  const [count, setCount] = React.useState(0);
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Clicked {count} times
    </button>
  );
}

When the button clicks, React generates a new virtual tree with the incremented count, compares it to the previous tree in ReactFiberBeginWork.js, and determines only the text node requires updating. The reconciler then queues this minimal change for the commit phase.

List Rendering and the Key Prop

The key prop provides stable identity for list items, enabling efficient reordering:

function TodoList({ items }) {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.text}</li>
      ))}
    </ul>
  );
}

According to the reconciliation logic in packages/react-reconciler/src/ReactChildFiber.js, React matches elements by key rather than position. This allows the reconciler to preserve component state when items move, inserting or removing only changed nodes rather than re-rendering the entire list.

Building Custom Renderers

The reconciler package exposes createRenderer for custom host environments:

import { createRenderer } from 'react-reconciler';

const hostConfig = {
  createInstance(type, props) {
    // Create host instance (e.g., canvas shape, WebGL object)
    return { type, props };
  },
  appendChild(parent, child) {
    // Append to host tree
  },
  // Additional host config methods...
};

const MyRenderer = createRenderer(hostConfig);

// Usage
const container = MyRenderer.createContainer(rootInstance);
MyRenderer.updateContainer(<App />, container);

This pattern, defined in packages/react-reconciler/src/ReactFiberReconciler.js, allows third-party renderers to leverage React's reconciliation algorithm while providing custom host-environment implementations via the ReactFiberConfig interface.

Key Source Files in the React Repository

The reconciliation algorithm spans several critical files in the facebook/react repository:

File Role
packages/react-reconciler/src/ReactFiberReconciler.js Main entry point that creates roots and schedules updates via updateContainer
packages/react-reconciler/src/ReactFiberWorkLoop.js Implements the work-loop scheduler that drives the render and commit phases
packages/react-reconciler/src/ReactFiberBeginWork.js Handles the render phase "begin work" logic, comparing current and new fibers
packages/react-reconciler/src/ReactFiberCommitWork.js Manages the commit phase, applying DOM mutations and running side-effects
packages/react-reconciler/src/ReactInternalTypes.js Defines Flow/TypeScript types for Fiber nodes, lanes, and update queues
packages/react-reconciler/src/ReactFiberConfig.* Host-configuration interface for different renderers (DOM, Native, custom)

These files collectively implement the reconciliation process that enables React's high-performance UI updates.

Summary

  • Reconciliation in React is the diffing algorithm that compares new virtual DOM trees against previous ones to compute minimal UI updates.
  • The process relies on three key invariants: type identity for component reuse, key props for stable list item identity, and depth-first child processing.
  • Internally, the Fiber architecture in packages/react-reconciler represents components as linked nodes, enabling incremental rendering and concurrency.
  • The algorithm splits work into a render phase (pure, interruptible) and a commit phase (synchronous side-effects), defined in ReactFiberBeginWork.js and ReactFiberCommitWork.js respectively.
  • Third-party renderers can leverage the same reconciliation logic via the react-reconciler package and a custom host config.

Frequently Asked Questions

What triggers reconciliation in React?

Reconciliation begins whenever React detects a state or prop change. Calling setState in class components, invoking a useState setter in function components, or receiving new props from a parent component schedules an update. The reconciler in packages/react-reconciler/src/ReactFiberReconciler.js then creates a new virtual tree and initiates the diffing process.

How does the key prop affect reconciliation?

The key prop provides stable identity for elements within lists or dynamic children. During reconciliation, React matches elements by key rather than by their position in the array. This allows the reconciler to preserve component state when items move, inserting or removing only the changed nodes rather than re-rendering the entire list. Without keys, React defaults to index-based matching, which can cause state bugs and performance issues.

What is the difference between reconciliation and rendering?

Rendering refers to the process of calling component functions to produce React elements (the virtual DOM tree). Reconciliation is the algorithm that compares the newly rendered tree with the previous one to determine what changed. While rendering produces the description of the UI, reconciliation computes the minimal set of mutations needed to update the actual host environment, such as the browser DOM or native views.

Can reconciliation be paused or interrupted?

Yes. Since the introduction of the Fiber architecture in React 16, reconciliation is designed to be incremental and interruptible. The render phase (the "begin work" logic in ReactFiberBeginWork.js) is pure and side-effect-free, allowing React to pause work, handle higher-priority updates like user input, and resume later. However, the commit phase (in ReactFiberCommitWork.js) is synchronous and cannot be interrupted to ensure UI consistency.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →