There's no "old way" snippet for this one. JSI and bridgeless mode are architecture, not an API you call, so the JS you write looks identical — what changed is the path it takes to reach native code underneath.
#The old way
Every native call went through JSON. A module method, a view update, an event: serialized to a string, pushed onto a queue, flushed once per frame over "the bridge."
The two runtimes never touched. Everything was async and string-based, which capped call throughput and made a truly synchronous native call, like measuring a view mid-render, impossible.
#The new way
JSI is a C++ interface. The JS engine holds direct references to native "host objects" and calls C++ functions synchronously, with no serialization and no queue in between.
Bridgeless mode goes further and deletes the legacy bridge module, routing TurboModules, Fabric, and events through JSI instead. Now a method can hand back a real value synchronously instead of a promise:
import { TurboModuleRegistry, type TurboModule } from 'react-native';
export interface Spec extends TurboModule {
getConstants(): { deviceModel: string; isTablet: boolean };
multiplySync(a: number, b: number): number;
}
export default TurboModuleRegistry.getEnforcing<Spec>('DeviceUtils');
import DeviceUtils from './NativeDeviceUtils';
function renderLabel(): string {
const { deviceModel } = DeviceUtils.getConstants();
const doubled = DeviceUtils.multiplySync(21, 2);
return `${deviceModel}: ${doubled}`;
}
multiplySync returns a plain number, right there in the call. The old bridge couldn't do that: any native round trip needed an async callback or a promise.
#Why it matters
- Synchronous native calls become possible. Layout measurement during render depends on exactly that.
- No JSON stringify/parse overhead per call between JS and native.
- Bridgeless removes an entire legacy subsystem, cutting startup memory and flattening the call stack that Fabric and TurboModules sit on.
#Gotcha
A synchronous JSI call blocks the JS thread until native returns. A slow synchronous host function — disk I/O, a heavy computation — freezes your JS thread's timers and animations for its whole duration.
Reserve sync methods for genuinely cheap operations. Anything slow stays a Promise-returning async method.