How does React Native's architecture actually work — bridge vs the new JSI/Fabric/TurboModules?
React Native looks like one JS thread talking to native views, but the real story is a messaging system that changed shape entirely — from an async JSON bridge to a synchronous C++ interface.
LEARN BY DOINGPut your intuition to work3 steps
How does React Native's architecture actually work — bridge vs the new JSI/Fabric/TurboModules?
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.React Native's pitch has always been "write JavaScript, get real native views," and most candidates can describe that much. What separates a senior answer is knowing the plumbing that makes it true: how a call made from the JS thread ever turns into a UIView or a android.view.View, and why Facebook spent years rewriting that plumbing from scratch. There are really two architectures to know here — the classic one almost every production app still runs today, and the New Architecture (JSI, TurboModules, Fabric) that is now the default for new projects.
#The classic architecture: three threads and a bridge
Classic React Native runs (at least) three threads. The JS thread runs your application code and the React reconciler on top of a JS engine (historically JavaScriptCore, now usually Hermes). The Shadow thread runs Yoga, the C++ flexbox engine that turns your styles into a layout tree. The main/UI thread owns the actual native views — UIView on iOS, View on Android — and is the only thread allowed to touch them.
None of those threads share memory directly. Every time the JS thread needs something from native — call a native module, request a layout measurement, mutate the view tree — the message has to be serialized to JSON, pushed onto a queue, and batched: React Native does not send messages one at a time, it drains the queue once per JS event loop tick to amortize the cost of crossing the bridge. On the other side, native deserializes the JSON, does the work, and if a response is expected, serializes a reply and sends it back the same way.
That "no synchronous call" line is the part that actually hurts in production. Anything that needs a native answer right now — measuring a view before deciding how to animate it, reading a scroll offset mid-gesture, driving a shared-element transition — has to wait at least one bridge round trip, and under load (a long list rendering, several native modules firing at once) that queue backs up. This is the concrete mechanism behind the jank that gave React Native its early reputation, not something vaguer like "JavaScript is slow."
#The New Architecture: JSI replaces the bridge, not just speeds it up
The fix was not a faster bridge — it was removing the bridge as a concept. JSI (JavaScript Interface) is a C++ layer embedded directly in the JS runtime that lets a JS object hold a real reference to a C++ object (a HostObject) and call its methods directly, synchronously, with no serialization. A JSI call is a C++ function call, not a JSON message on a queue — arguments and return values cross the boundary as actual values, not text.
TurboModules are native modules rebuilt on top of JSI. Two things change versus the old NativeModules: they are lazily loaded (a module is only instantiated the first time JS touches it, which is why New Architecture apps have a visibly faster cold start on module-heavy apps), and their JS-facing interface is generated by Codegen from a typed spec (Flow or TypeScript), so the native and JS sides of a module are checked against the same contract instead of trusting a hand-written bridge signature.
Fabric is the renderer built the same way. In the classic architecture, the "Shadow Tree" and UIManager also crossed the bridge to commit view mutations to the main thread. Fabric keeps the shadow tree in C++, shared directly with JS through JSI, so a layout can be measured or committed synchronously when the situation calls for it, and view mutations no longer wait on a batched, serialized queue. Fabric is also what lets React Native plug into React's Fiber concurrent model properly — priorities and interruption can be respected across the JS/native boundary instead of stopping at it.
Put together, RN 0.74+ can run bridgeless: the legacy bridge object is not even instantiated, and JSI is the only path between JS and native. Everything above — JSI, TurboModules, Fabric, Codegen, bridgeless mode — is what people mean when they say "the New Architecture"; it shipped as the default for new apps, with most existing libraries reached through an interop layer while their maintainers ported them natively.
#What this actually buys you, concretely
A strong answer names real consequences, not just component names: synchronous layout measurement without an extra round trip, meaningfully lower JSON ser/deserialize cost on apps that push a lot of data across the boundary (chat apps, apps with big lists, anything calling native modules in a hot loop), faster cold start from lazy TurboModules instead of eagerly constructing every native module, and less memory churn because large values (like image buffers) can be referenced instead of copied through a JSON string. The honest caveat worth adding: adoption was gradual, some third-party native libraries lagged behind on shipping true Fabric components, and the interop layer — while it made most existing libraries "just work" — is a real migration detail, not a footnote, for a team maintaining a large RN codebase today.
🧠 Bridge vs. New Architecture
0/3 · 0/3 answered1. What was the fundamental limitation of the classic React Native bridge?
2. Which statement correctly distinguishes JSI, TurboModules, and Fabric?
3. Why do TurboModules improve cold start time versus classic native modules?