Dave HunterBlog

Why React Native (and TurboModules)?

I’ve spent most of my career working in “native” worlds: C++, Objective-C, Swift, and the various platform APIs that come with them. I still run into snobbery around React Native—the idea that it’s somehow not “real” software in the same way native code is.

I’ve written a lot of native UI. I still like native UI. In many cases, it is better.

But this debate is old. And more importantly, it misses the point of what React Native—especially with TurboModules—actually enables.

This Is an Old Argument

Before mobile, I spent years working on desktop applications, mostly trying to ship the same product on both macOS and Windows. Back then, this exact argument showed up all the time.

Some teams used technologies like Java. Others used frameworks like Qt. Some built their own cross-platform UI layers. I’ve worked on several of those systems.

I’ve always preferred cross-platform approaches that don’t trap you. The good ones make it easy to drop down to platform APIs when you need to—whether that’s for performance, platform-specific UX, or access to some niche system feature. In practice, there are always places where “just use the abstraction” stops being the right answer.

React Native fits this model. You can keep most of your UI shared, but you can also make a screen—or even just a single view—fully native when it makes sense, without rewriting the entire app or fighting the framework.

The same set of truths always came up, then and now:

None of this is theoretical. It shows up directly in how long features take to ship and how hard they are to keep working everywhere.

Five UI Stacks and a C++ Core

At Autodesk, I was Principal Engineer and Engineering Manager on SketchBook, a popular multi-platform drawing app. Architecturally, SketchBook had a large shared C++ core, with platform-specific UI layers on top.

Five of them, to be precise: Windows, macOS, iOS, Android, and UWP.

That setup worked. But from an engineering perspective, it was a maintenance nightmare. Any non-trivial feature meant touching multiple UI codebases, each with their own quirks, bugs, and limitations. Even small changes were expensive. Bigger changes were exhausting.

At one point, I seriously considered redoing all of the UI in Qt. And to be clear: I actually like Qt. But Qt on iOS is hot garbage.

Around that same time, Autodesk had a close relationship with Microsoft, and I started paying attention to the work they were doing to bring React Native to macOS and Windows. I also noticed the broader effort inside React Native to move more of the core toward shared, modern C++.

That combination stuck.

A Pragmatic View of React Native

I ended up leaving Autodesk when SketchBook was sold. Not long after that, I started working seriously with React Native at Shopify and Walmart—after a brief detour working on Unreal Engine at Epic.

Native UI is still great. In some places, it’s the right choice.

But there’s a lot of UI in real products that is fiddly, repetitive, and not where you want to spend your most expensive engineering time—especially if it means maintaining the same thing in two or three or five different codebases.

React Native is good at being a single, shared UI layer for that kind of work.

And no, that doesn’t make it “fake.” It makes it pragmatic.

Where TurboModules Change the Story

The most interesting part, especially as a C++ engineer, is TurboModules.

In the apps I’ve been working on recently, there’s a lot of hardware, networking, and performance-sensitive code involved. That’s not something you want to write in JavaScript. And it’s not something you want to duplicate separately for every platform if you can avoid it.

At a high level, TurboModules are a typed, direct bridge between JavaScript and native code. Instead of going through the old, stringly-typed, reflection-heavy bridge, you define an interface once and React Native generates the glue that connects JavaScript to your C++ (or Obj-C/Java/Kotlin) implementation.

On the C++ side, you’re just writing normal C++: real types, real functions, real libraries. You can call into your existing code, link against native SDKs, talk to hardware, do heavy computation, or integrate third-party libraries without contorting everything to fit a JavaScript-shaped API. You also don’t have to worry about platform-specific mechanisms for getting into native code—if you’ve ever dealt with the Android NDK and JNI, you’ll appreciate how much friction that removes.

Unlike the legacy bridge, TurboModule calls can happen synchronously on the JavaScript thread. That changes how you structure things: you can write code that looks like normal function calls instead of everything being forced through async message passing. If you want to move work off-thread, you still can—callbacks, promises, and listener-style APIs all work fine—you just need to make sure you marshal results back to the JavaScript thread when you’re done.

From the React Native side, those modules show up as regular, typed interfaces. You call them from JavaScript or TypeScript, you get proper tooling and autocomplete, and the calls go straight through to native code without the old serialization bottlenecks.

The important part isn’t just performance—though that helps. It’s that this lets you structure your app the same way you’d structure any cross-platform native system: a shared, testable C++ core with thin platform bindings and a UI layer on top. React Native just happens to be a very productive place to put that UI.

Why React Native?

If you’re a C++ or platform engineer who’s skeptical of React Native, I get it. I was too. I still don’t think it’s the right answer for everything.

But if you care about:

Then React Native, paired with TurboModules, is a solid, practical architecture.

It’s not a silver bullet, and it’s not for every project. But for teams that want to keep serious native and C++ code while collapsing some or all of the UI into a single layer, it’s a surprisingly effective compromise.