skip to content

Runtime Layers

How React Native runs your code: the JS and UI threads, JSI calls into C++, the Fabric renderer, Hermes and the New Architecture move. Interviewers use it to test depth past the component API.

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

explore

questions

20

In React Native, what is the Fabric renderer, and what does it enable that the legacy renderer could not?

level: juniorimportance: must knowfreq 60%

answer

  1. the New Architecture's renderer
  2. written once in C++
  3. immutable shadow tree
  4. layout readable synchronously
  5. Suspense and Transitions work

basics

~20 s

Fabric is React Native's New Architecture renderer: a shared C++ core that turns React's tree into native views through an immutable shadow tree. It enables synchronous layout reads, concurrent features such as Transitions and Suspense, and flattening on both platforms.

solid answer

~40 s

Fabric is the renderer of React Native's New Architecture and, since 0.82, the only one. Its core is written once in C++ and shared across platforms. For each host component React renders it creates an **immutable shadow node**, runs **Yoga** layout on the resulting tree and mounts only the diff as native views; React drives it directly through JSI. Because the tree is immutable and lives in C++, layout can be read **synchronously** (so `useLayoutEffect` can position a tooltip before it is shown), several versions of the UI can be in progress at once, which makes **Transitions**, **Suspense** and interruptible rendering work, and updates are automatically batched. It also brings view flattening to iOS, which the legacy renderer only did on Android.

go deeper

for a junior

Say what Fabric is: the New Architecture's renderer, written in C++, turning React components into real native views.

for a middle

Explain the immutable shadow tree and connect it to synchronous layout reads, automatic batching and concurrent features such as Suspense.

for a senior

Use Fabric's guarantees in design: position overlays in useLayoutEffect, rely on Transitions for heavy screens, and know which behaviors changed for old libraries.

for a principal

Weigh the platform consistency of a shared C++ renderer against the cost of libraries that still depend on legacy rendering internals.

## What a renderer does in React Native React itself does not know how to draw anything. A **renderer** takes the tree of elements React produces and turns it into something on screen: ReactDOM turns it into DOM nodes, and React Native's renderer turns it into **host views**, the real platform views such as `android.view.ViewGroup` and `UIView`. **Fabric** is React Native's renderer in the New Architecture. It replaced the legacy renderer, which was implemented separately for each platform, talked to native code over the asynchronous bridge, and kept a single mutable copy of the UI in the native view hierarchy. Since React Native 0.82 Fabric is the only renderer. ## How Fabric is built - **A shared C++ core.** The renderer's logic (shadow trees, layout, diffing) is written once in C++ and runs the same way on iOS, Android and other supported platforms, instead of being re-implemented per platform. - **An immutable shadow tree.** For every host component React renders (`View`, `Text`, `Image`), Fabric creates a C++ **shadow node**. Nodes are never edited in place: an update clones the changed nodes into a new tree and shares the rest. - **Yoga for layout.** The flexbox engine computes each node's size and position on the shadow tree before anything is mounted. - **JSI to React.** React calls into the C++ renderer directly through JSI, synchronously, instead of sending serialized messages. ## What that design enables | Capability | Why it depends on Fabric | |---|---| | **Synchronous layout reads** | Layout lives in the C++ shadow tree, so `measure` or `getBoundingClientRect` can answer immediately, for example inside `useLayoutEffect` | | **Concurrent React features** | Immutable trees let React keep several versions of the UI in progress, so **Transitions**, **Suspense** and interruptible rendering work | | **Automatic batching** | Several state updates render as one commit, so fewer intermediate states reach the screen | | **Prioritized updates** | An urgent update, such as a response to a tap, can interrupt a low-priority render | | **View flattening on both platforms** | Layout-only views are removed from the host hierarchy by the C++ core; the legacy renderer did this only on Android | | **Consistency** | One C++ implementation means fewer platform-specific rendering differences | The legacy renderer could not offer the first four because it kept one mutable copy of the UI in native code and could only be updated through asynchronous messages. There was no way to read layout synchronously and no way to keep an alternative version of the tree while the current one stayed on screen. ## What stays the same 1. You write the same components: `View`, `Text`, `Image`, `ScrollView` and your own function components. 2. Styles and flexbox layout keep their React Native semantics; Yoga computed layout before Fabric too. 3. Most apps notice Fabric through behavior (fewer flickers, working `useLayoutEffect`, Suspense) rather than through new APIs. ## Common confusions - **Fabric is not a new UI toolkit.** It still produces native platform views; it does not draw its own pixels. - **Fabric is not the same thing as JSI.** JSI is the C++ interface to the JavaScript engine; Fabric is the renderer built on top of it, alongside Turbo Native Modules. - **Fabric is not optional in current versions.** From React Native 0.82 the New Architecture, and therefore Fabric, cannot be switched off. - **Fabric is not Hermes.** Hermes is the JavaScript engine that runs your bundle; Fabric talks to whichever engine is running through JSI and does not depend on its internals. - **Fabric does not make your JavaScript multi-threaded.** It makes the renderer's data structures safe to use from more than one thread. ## In an interview A junior answer names Fabric as the New Architecture's C++ renderer that turns React's tree into native views. A strong answer adds the one design decision everything else follows from, the **immutable shadow tree**, and one concrete consequence, such as positioning a tooltip correctly in `useLayoutEffect` because layout can now be read synchronously.

  • Why did React Native's legacy renderer not support Suspense and Transitions fully?
    Concurrent features need React to prepare a new version of the UI while the current one stays on screen, and to abandon or interrupt that work. The legacy renderer kept a single mutable copy of the UI in native code, updated through asynchronous messages, so there was nowhere to hold an alternative tree. Fabric's immutable shadow trees make several in-progress versions possible.
  • In React Native, is Fabric the same thing as JSI?
    No. JSI is the C++ interface that lets JavaScript and native code call each other directly. Fabric is the renderer that uses JSI to receive React's updates, and Turbo Native Modules are the module system that uses it too. JSI is the foundation; Fabric is one of the systems built on it.

saying these in an interview costs you the question

  • Fabric draws its own pixels instead of creating native platform views.
  • Fabric and JSI are two names for the same thing.
  • Fabric is an optional renderer you can still switch off in 0.87.
  • Fabric makes React Native run JavaScript on several threads.
  • View flattening existed on iOS long before Fabric.
open as a page

What is Hermes in React Native, and why does it make a release build start faster than an engine that parses JavaScript source at launch?

level: juniorimportance: must knowfreq 72%

basics

~20 s

Hermes is React Native's default JavaScript engine. In release builds its compiler, hermesc, turns the Metro bundle into bytecode on the build machine, so at launch the device runs ready bytecode instead of parsing and compiling JavaScript source.

open as a page

In React Native, what work runs on the JavaScript thread and what runs on the UI (main) thread?

level: juniorimportance: must knowfreq 75%

basics

~20 s

The JavaScript thread runs your bundle: React rendering, state updates, event handlers, timers and fetch callbacks. The UI (main) thread is the only one that creates and mutates native views, and it handles raw touches, native scrolling and native animations.

open as a page

In React Native, what did JSI change compared with the legacy bridge for calls between JavaScript and native code?

level: middleimportance: must knowfreq 75%

basics

~20 s

The legacy bridge sent serialized, batched messages asynchronously, so native calls normally answered through callbacks or promises. JSI lets JavaScript call C++ host functions synchronously and hold references to C++ host objects, with no serialization step.

open as a page

In React Native 0.87, can a team still switch the New Architecture off, and what happens if gradle.properties sets newArchEnabled=false?

level: middleimportance: must knowfreq 62%

basics

~20 s

No. The New Architecture is the only architecture since React Native 0.82: newArchEnabled=false on Android and RCT_NEW_ARCH_ENABLED=0 on iOS are ignored with a warning, and the app still runs on it, with old libraries loaded through interop layers.

open as a page

In a React Native stopwatch app, why does the running timer freeze while a large JSON response is parsed, though ScrollView still scrolls?

level: middleimportance: must knowfreq 60%

basics

~20 s

JSON.parse runs synchronously on the single JavaScript thread, so no setInterval callback, state update or re-render can run until it returns. Scrolling is performed natively on the UI thread, so it keeps working while JS-driven updates stall.

open as a page

In a React Native 0.87 app, does JavaScript still talk to native code through the bridge, and what replaced it?

level: juniorimportance: should knowfreq 50%

basics

~10 s

No. React Native 0.87 runs bridgeless: JavaScript calls Turbo Native Modules and drives the Fabric renderer through JSI, with no serialized message queue. Libraries still written for the bridge work through interop layers.

open as a page

In React Native's Fabric renderer, what happens in the render, commit and mount phases after a component's state changes?

level: middleimportance: should knowfreq 40%

basics

~20 s

Render clones the changed host components' shadow nodes into a new immutable tree. Commit runs Yoga layout and promotes it as the next tree. Mount diffs it against the tree on screen and applies only the resulting mutations to native views.

open as a page

In React Native, how do you confirm Hermes is running, and why can that check pass while a transit-timetable app still cold-starts slowly?

level: middleimportance: should knowfreq 38%

basics

~20 s

Check the HermesInternal global, which only Hermes defines. It proves the engine, not the input: debug builds run development source from Metro, and non-standard bundle loading can skip the precompiled bytecode, so measure a release build that ships the .hbc.

open as a page

How do React Native's interop layers let a library written for the old architecture run on the New Architecture, and what can they not provide?

level: middleimportance: should knowfreq 45%

basics

~20 s

Interop layers adapt old-architecture code: legacy native modules are served through NativeModules and legacy view managers are hosted in a Fabric wrapper. They cannot provide custom shadow nodes, concurrent features, synchronous typed calls or codegen type safety.

open as a page

In a React Native 0.87 note-taking app, how do you position a tooltip under its anchor before the first frame is shown, without a flicker?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Measure the anchor's host View ref inside useLayoutEffect with getBoundingClientRect or measureInWindow, then set the tooltip's placement there. Fabric answers synchronously from the committed shadow tree, so the corrected position commits before the first frame.

open as a page

In React Native 0.87, what does it take to keep an app on JavaScriptCore instead of Hermes, and why do most teams stop doing so?

level: seniorimportance: should knowfreq 30%

basics

~20 s

JavaScriptCore is no longer in core since 0.81: an app must add @react-native-community/javascriptcore and select it in the build. Most teams move to Hermes V1 instead, which core ships, tests and precompiles to bytecode for faster startup.

open as a page

A React Native barcode-scanner library moves from bridge events to a JSI HostObject: what changes, and what threading rule must its C++ code obey?

level: seniorimportance: should knowfreq 25%

basics

~20 s

Scans stop being serialized, queued bridge events: JavaScript holds a C++ host object and reads its state synchronously. The rule: jsi::Runtime must not be used concurrently, so the camera thread schedules work onto the JS thread instead of touching the runtime.

open as a page

After a React Native upgrade, what symptoms show that a library still relies on legacy-architecture APIs, and how do you trace each symptom to its cause?

level: seniorimportance: should knowfreq 32%

basics

~20 s

Legacy dependence shows as Android compile errors on classes removed in 0.84 or 0.85, iOS build failures now that legacy code is compiled out, 'not available in the new architecture' errors, nil-returning bridge-proxy calls and Unimplemented component placeholders.

open as a page

Before upgrading a React Native ride-hailing app that depends on 40 third-party libraries, how do you audit them for New Architecture compatibility?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Drop pure-JavaScript libraries, check each native one's New Architecture status in React Native Directory, its codegenConfig and release notes, then run every flow on the New Architecture and sort libraries into supported, interop-only, broken or replace.

open as a page

In React Native's Fabric renderer, which thread runs render, commit and mount, and when can the whole pipeline run synchronously on the UI thread?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Normally render and commit (including Yoga layout) run on the JavaScript thread and mount runs on the UI thread. For a high-priority discrete event originating on the UI thread, Fabric can run render, commit and mount synchronously on the UI thread.

open as a page

When a third-party library blocks a React Native app's move to the New Architecture, how do you decide whether to replace it, fork it, or port it yourselves?

level: principalimportance: should knowfreq 22%

basics

~20 s

Weigh the feature's importance, a maintained alternative, the native surface and whether the team can own it: replace when a good alternative exists, fork or port when none does and you can maintain it, and treat interop as borrowed time.

open as a page

In React Native's Fabric renderer, what is view flattening, and when do you need collapsable={false} on a View?

level: middleimportance: nice to knowfreq 25%

basics

~10 s

View flattening lets Fabric skip creating native views for layout-only Views, folding their layout into their children during diffing. Set collapsable={false} when native code needs that View to exist as a real platform view.

open as a page

How did React Native's legacy bridge batch JavaScript-to-native calls in its MessageQueue, and why did the arguments have to be serializable?

level: middleimportance: nice to knowfreq 25%

basics

~20 s

MessageQueue recorded each call as a module id, method id and arguments, and handed the batch to native code on the next native-to-JS return or after 5 ms. Arguments crossed as JSON-compatible data, so functions, NaN and native objects could not.

open as a page

In a React Native app on Hermes, how does the garbage collector keep pauses off the JS thread, and when does React Native trigger a collection itself?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

Hermes's Hades collector does most old-generation marking and sweeping on a background thread, so the JS thread pauses only briefly, at some throughput cost. React Native also requests a collection on severe Android onTrimMemory levels and, since 0.81, on iOS memory warnings.

open as a page