It’s been a while since React Native's new architecture has been largely adopted by the ecosystem, but there’s still a lack of understanding in how this new Architecture actually improves performance.
In this article, we’ll focus on the solution Meta built: a shared C++ communication layer powered by JSI.
RN New Architecture Myth
The myth is that Meta simply “removed the Bridge and added C++”. The reality is more interesting. React Native introduced a shared C++ communication layer that allows JavaScript and Native code to interact through the same runtime, unlocking capabilities that were previously difficult or impossible to build.
What actually happened? (Introduction of JSI)
Meta introduced JSI, JavaScript Interface, which is a C++ abstraction layer that allows React Native to communicate with any JavaScript engine (RN uses hermes engine). Let’s dig deeper into how JSI facilitate the JavaScript — Native & Native — JavaScript communication
How JSI works in React Native?
To understand the working of JSI in React Native, let’s first understand at how JavaScript handles memory. In JavaScript, almost everything is an object. When you write const user = { name: “Sankalp” }, the variable user doesn’t actually hold the text* "Sankalp*". Instead JavaScript creates a box in your phone’s memory, puts the data inside and user simply becomes a **reference, **an arrow pointing to that memory address. The core difference between the Old Architecture and the New Architecture comes down to how we treat those memory addresses.
In old architecture, Native code (C++ / Java, Objective C) was not allowed to look into JavaScript’s memory. If JS wanted to send user object to native side, it couldn’t just handover the memory address. Instead, JS had to stringify the object into JSON (making a photocopy), send that over the bridge and then Native side has to parse the string and allocate a brand new box in the Native memory. That makes the communication expensive.
In new architecture, JSI essentially provides a set of rules that allows C++ to safely hold an arrow pointing directly to the JavaScript engine’s memory.
When people say “Shared C++ runtime”, it means:
- When JS passes an object to C++, JSI creates a type handle called
jsi:: Object, think of it like a library card and not a photocopy of book. - This handle is GC aware, i.e. Hermes knows that C++ is holding it and will not garbage collect the underlying JS Object as long as the handle is alive.
- When C++ needs to read
user.nameit calls through this handle synchronously. Hermes resolves this value synchronously without copying, serializing or waiting.
Note: JSI enables synchronous communication, but not every native call becomes synchronous. Heavy operations like network requests or file I/O are still async, which means blocking the JS thread for those would freeze your UI. The real win is that synchronous access is now possible by design, whereas the old Bridge made it structurally impossible regardless of your use case
Flipping the script: Native Objects in JS
The real magic is that this works in reverse. JSI creates C++ objects called HostObject and expose them to JavaScript as regular JS objects. In the JavaScript side, it just looks like a normal JS object. But under the hood whenever you call a method under the object, the JS engine follows the memory address directly into the C++ realm.
The execution of native code from C++ HostObjects works differently in case of iOS and Android.
iOS: The jump from C++ code to native Apple Code is non-existent. This is entirely thanks to a language called Objective C++ (.mm file extension). It is a hybrid compiler feature created by Apple which allows you to write raw C++ and Objective-C code in same file side by side. How it works here is that both Objective-C and C++ code exists in same memory space.
When your JavaScript calls a method on JSI HostObject , execution drops synchronously into a C++ function. If that function is inside an .mm file, you can directly invoke an iOS Native API on the very next line.
Android: In this case, Android’s core OS and UI layers are written in Java and Kotlin which runs inside Android Runtime(ART) virtual machine. C++ and Java doesn’t live in the same memory. C++ manages it’s own raw memory whereas Java uses a strict Garbage Collector (GC). You cannot simple give C++ memory pointer to Java. To solve this **JNI **comes into the picture which is Android’s official translator between the C++ and Java Virtual Machine(JVM).
How JNI (Java Native Interface) works
When C++ needs to call a Java/Kotlin method, it uses JNI to transition execution into the JVM. The C++ thread doesn’t pause, it crosses a runtime boundary, continuing execution now inside the JVM context, runs the Java code synchronously, and then returns across that boundary back to C++. React Native uses Meta’s fbjni library to make this boundary crossing cleaner: it wraps Java objects in smart C++ pointers, handles type conversion safely, and avoids the boilerplate of raw JNI lookups.
When your JSI (C++) layer needs to trigger an Android-specific API (Java/Kotlin), it doesn’t use raw JNI directly. It uses fbjni to safely, quickly, and cleanly pass that execution over the boundary.

Understanding the internals of React Native and how JS to Native communication will unlocks the what React Native can actually do today. For years, we built React Native apps by trying to minimize our trips across the Bridge. Today, thanks to the shared C++ runtime of JSI, TurboModules, and Fabric, that mental model is obsolete. Whether you are directly triggering iOS APIs through Objective-C++ or safely navigating the Android JVM via fbjni, you now have direct, low-overhead access to device internals — synchronous where it makes sense, asynchronous where it doesn’t.
If you find this article helpful, do give it a clap and feel free share!
Comments
Loading comments…