Skip to content

Fiber Architecture — Complete Guide

DodaTech Updated 2026-06-28 7 min read

In this tutorial, you will learn about Fiber Architecture. We cover key concepts, practical examples, and best practices to help you master this topic.

Fiber is React's reimplementation of the reconciliation engine that enables incremental rendering, work prioritization, and concurrency without blocking the main thread.

What You'll Learn

  • What Fiber is and why React replaced the stack reconciler
  • How Fiber enables incremental rendering
  • How work prioritization works in Fiber
  • How Fiber handles interruptions and resumption

Why It Matters

The stack reconciler blocked the main thread during rendering, causing jank in animations and input handling. Fiber fixes this by breaking work into units that can be paused and resumed.

flowchart TD
  A[Fiber Reconciliation] --> B[Begin Work Phase]
  B --> C{Time slice remaining?}
  C -->|Yes| D[Process next fiber node]
  C -->|No| E[Yield to browser]
  E --> F{More work?}
  F -->|Yes| B
  F -->|No| G[Complete Phase]
  G --> H[Commit Phase]
  H --> I[DOM mutations applied]

What Is Fiber

Fiber is a Unit of Work in React's reconciliation. Each fiber node corresponds to a component instance or DOM element.

// Simplified fiber node structure
class FiberNode {
    constructor(tag, pendingProps, key) {
        this.tag = tag;           // Component type (Function, Class, Host, etc.)
        this.key = key;           // Unique identifier
        this.type = null;         // The component function or element type
        this.stateNode = null;    // Reference to the real DOM node or component instance

        // Tree structure
        this.return = null;       // Parent fiber
        this.child = null;        // First child fiber
        this.sibling = null;      // Next sibling fiber

        // Work-related
        this.pendingProps = pendingProps;  // New props to process
        this.memoizedProps = null;         // Props from previous render
        this.memoizedState = null;         // State from previous render

        // Effects
        this.effectTag = null;    // Placement, Update, Deletion, etc.
        this.nextEffect = null;   // Next fiber in effects list

        // Priority
        this.lanes = NoLanes;     // Which updates this fiber is part of
        this.childLanes = NoLanes; // Which updates children are part of
    }
}

// Fiber creates a linked list tree (not recursive)
// This allows walking the tree iteratively instead of recursively
// Recursive calls cannot be interrupted. Linked list traversal can.

From Stack Reconciler to Fiber

The stack reconciler used recursive calls that could not be interrupted. Fiber uses a Linked List that can be paused.

// Stack reconciler (old): Recursive, cannot be interrupted
function stackReconcile(element, container) {
    // Recursive call — cannot pause once started
    const dom = createDOM(element);
    element.children.forEach(child => {
        stackReconcile(child, dom);  // Deep recursion
    });
    container.appendChild(dom);
    // If this takes 200ms, the main thread is blocked for 200ms
}

// Fiber reconciler (new): Iterative, can be interrupted
function fiberReconcile(rootFiber) {
    let nextUnitOfWork = rootFiber;

    function workLoop(deadline) {
        // Process fibers until time runs out
        while (nextUnitOfWork && deadline.timeRemaining() > 1) {
            nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
        }

        if (nextUnitOfWork) {
            // More work remaining, request next frame
            requestIdleCallback(workLoop);
        } else {
            // All work done, commit
            commitRoot();
        }
    }

    // Start work loop with idle callback
    requestIdleCallback(workLoop);
}

Work Prioritization with Lanes

Fiber uses lanes to prioritize updates. Higher priority updates interrupt lower priority work.

// Lanes represent priority levels
const Lanes = {
    NoLanes: 0b0000000000000000000000000000000,
    SyncLane: 0b0000000000000000000000000000001,        // Highest priority
    InputContinuousLane: 0b0000000000000000000000000000010, // Input events
    DefaultLane: 0b0000000000000000000000000000100,      // Normal updates
    TransitionLane: 0b0000000000000000000000000001000,   // Transitions
    IdleLane: 0b0000000000000000000000010000000,         // Low priority
    OffscreenLane: 0b0000000000000000000010000000        // Hidden content
};

// Priority-based scheduling
function scheduleUpdate(fiber, lane) {
    // Mark fiber with its lane priority
    fiber.lanes = mergeLanes(fiber.lanes, lane);

    // Bubble priority up to root
    let node = fiber;
    while (node.return) {
        node.return.childLanes = mergeLanes(node.return.childLanes, lane);
        node = node.return;
    }

    // Schedule render with appropriate priority
    if (lane === SyncLane) {
        // Synchronous: process immediately
        performSyncWork();
    } else {
        // Deferred: schedule with requestIdleCallback
        scheduleCallback(lane, performConcurrentWork);
    }
}

// If a Sync update comes in while processing a Default update:
// 1. Current work is paused
// 2. Sync work is processed
// 3. Sync work is committed (DOM updated)
// 4. Default work resumes from where it paused

The Work Loop in Detail

The work loop processes fibers in two phases: render and commit.

// Render phase (can be interrupted)
function performUnitOfWork(fiber) {
    // 1. Begin work on this fiber
    beginWork(fiber);

    // 2. If fiber has a child, process child next (depth-first)
    if (fiber.child) {
        return fiber.child;
    }

    // 3. No child: complete this fiber and move to sibling
    let current = fiber;
    while (current) {
        completeUnitOfWork(current);

        if (current.sibling) {
            return current.sibling;  // Process sibling next
        }

        // No sibling: go back to parent
        current = current.return;
    }

    // Reached the root: all work is done
    return null;
}

function beginWork(fiber) {
    // Determine if this fiber needs work
    if (fiber.lanes === NoLanes) {
        // No pending work, bail out
        cloneChildFibers(fiber);
        return;
    }

    // Process based on fiber tag
    switch (fiber.tag) {
        case FunctionComponent:
            // Call the function component
            const children = fiber.type(fiber.pendingProps);
            reconcileChildren(fiber, children);
            break;
        case HostComponent:
            // Create or update DOM element
            reconcileChildren(fiber, fiber.pendingProps.children);
            break;
        case ClassComponent:
            // Call render method
            const rendered = fiber.stateNode.render();
            reconcileChildren(fiber, rendered);
            break;
    }
}

// Commit phase (synchronous, cannot be interrupted)
function commitRoot(rootFiber) {
    // Walk the effect list and apply DOM mutations
    let effect = rootFiber.firstEffect;
    while (effect) {
        switch (effect.effectTag) {
            case 'PLACEMENT':
                // Insert new DOM node
                break;
            case 'UPDATE':
                // Update existing DOM node
                break;
            case 'DELETION':
                // Remove DOM node
                break;
        }
        effect = effect.nextEffect;
    }
}

How Fiber Enables Concurrent Rendering

Fiber's ability to pause and resume work enables React's concurrent features.

// Concurrent rendering: lower priority work yields to higher priority
// This is how useTransition works:

import { useTransition, useState } from 'react';

function SearchPage() {
    const [query, setQuery] = useState('');
    const [isPending, startTransition] = useTransition();

    function handleChange(e) {
        // High priority: update the input immediately
        setQuery(e.target.value);

        // Low priority: filter results (can be interrupted)
        startTransition(() => {
            setFilteredResults(filterData(e.target.value));
        });
    }

    // While the transition is pending, isPending is true
    // The input stays responsive because filtering yields
    return (
        <div>
            <input value={query} onChange={handleChange} />
            {isPending && <span>Updating...</span>}
            <ResultsList data={filteredResults} />
        </div>
    );
}

Common Mistakes

  1. Assuming Fiber makes all updates asynchronous (sync updates like useEffect are still synchronous).
  2. Thinking Fiber eliminates all re-render costs (it only distributes work over time).
  3. Using useTransition for every update (only use it for expensive, non-urgent updates).
  4. Expecting concurrent features to work without React 18+ and the new root API.
  5. Misunderstanding that Fiber is React-specific (other frameworks use different approaches).

Practice Questions

  1. What problem does Fiber solve? The stack reconciler blocked the main thread during rendering. Fiber enables incremental, interruptible rendering.
  2. How does Fiber achieve interruptibility? By using a linked list fiber tree instead of recursive calls, which can be paused and resumed.
  3. What are lanes in Fiber? Priority levels that determine which updates are processed first.
  4. What are the two phases of Fiber reconciliation? Render phase (interruptible) and commit phase (synchronous).

Challenge

Build a simplified Fiber-like reconciler that processes a component tree using a work loop with requestIdleCallback. Implement priority levels where sync updates interrupt lower priority work. Demonstrate by rendering a large list with a concurrent search filter.

FAQ

What is React Fiber?

Fiber is React's reconciliation engine that replaces the stack reconciler. It enables incremental, interruptible rendering and work prioritization.

How does Fiber improve performance?

Fiber breaks rendering into units of work that can be paused, prioritized, and resumed. This prevents long renders from blocking the main thread.

Is Fiber specific to React?

Yes. Fiber is React's internal implementation. Other frameworks like Vue and Preact use different reconciliation strategies.

Does Fiber affect how I write components?

Not directly. Fiber is an internal implementation detail. However, concurrent features like useTransition and Suspense depend on Fiber.

What is the difference between render phase and commit phase in Fiber?

The render phase builds the fiber tree and computes changes. It can be interrupted. The commit phase applies DOM mutations synchronously.

Mini Project

Build a simple Fiber-inspired renderer. Implement a work loop that processes virtual nodes one at a time using requestIdleCallback. Add priority lanes for urgent (input) vs non-urgent (list filtering) updates. Show a visual indicator when the renderer yields to the browser.

What's Next

Lesson 8: Diffing Strategies

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro