React Native Fabric and TurboModules Explained
Cover photo by Adi Goldstein on Unsplash
So, you are still dealing with that bridge bottleneck in your React Native app. I get it. The bridge has been the source of all our UI jank for years. Now we have Fabric and TurboModules, and everyone wants to know if they should jump ship to the new architecture yet.
Why change the bridge at all?
“The bridge is fine, why fix what isn’t broken?” You aren’t totally wrong. If your app is simple and performance isn’t a massive pain point, the legacy bridge works. It handles the serialization of JSON messages between the JS thread and the native side fine. But, it is inherently asynchronous and that causes latency. Fabric changes how the UI manager communicates with native, making it synchronous where it needs to be. This eliminates those frame drops during navigation or heavy UI updates.
Are TurboModules actually better?
Before, your native modules were initialized at startup. This bloated your app boot time because the JS engine had to load everything, even if you never touched the camera or the Bluetooth module. TurboModules allow for lazy loading.
// In the new architecture, you fetch the module only when neededconst MyNativeModule = TurboModuleRegistry.getEnforcing('MyNativeModule');This is a huge win for cold start times. I’ve seen some apps shave off nearly a second just by switching to this approach (though your mileage will vary depending on your dependency graph).
”Is this just going to break all my dependencies?”
This is where I have to be the bearer of bad news. Yes, it might. Migrating to the new architecture is not a simple toggle. If your app relies on older, unmaintained native libraries that haven’t adopted the new TurboModule or Fabric specs, you are going to be stuck writing your own shims or dealing with messy interop code. It’s a non-trivial amount of work. If you have a massive codebase with fifty plus native dependencies, don’t expect a weekend refactor.
So, when should I migrate?
If you are starting a greenfield project today, there is no reason to stay on the legacy architecture. Use the new one. The ecosystem is finally reaching a point of maturity where the common libraries are updated.
However, if you are maintaining a complex production application, be careful. I would suggest starting with a small migration of your most performance-critical screens (or just the boot sequence) rather than trying a full rip-and-replace. Is the documentation perfect? No. You will find yourself reading through GitHub issues more than official docs sometimes (we have all been there, wait, I mean, I have definitely spent too many nights doing that).
What about the overhead?
One thing I’m still figuring out is the long-term maintenance cost. Writing C++ for JSI interop is a different beast than writing standard bridge modules. If your team doesn’t have anyone comfortable with C++, you might hit a wall when something goes wrong at the native layer.
Are you ready to deal with potential build failures and C++ compiler errors to get that extra performance? For me, the answer is usually yes, because smooth navigation is worth almost any amount of setup pain. For you, it depends on whether your users are actually complaining about that stuttering list view.
Have you tried migrating a production app yet? I would love to hear if the performance gains matched your expectations.