React Native performance advice usually comes in two flavors: "memoize harder" or "rewrite it native." After 16+ years shipping mobile products, I think both miss the practical middle path the new architecture gave us: keep the product in TypeScript, move the one hot path to C++, measure, stop.
On a recent production app, that approach — custom C++ Nitro Modules over JSI for the hottest code paths — bought roughly 40% better computational efficiency in those paths, without changing how the product team ships everything else.
The decision rule
Not everything deserves C++. Almost nothing does, actually. My rule of thumb for what leaves JavaScript:
- It runs per frame, per keystroke, or per list item → candidate for native.
- It parses, transforms, or diffs nontrivial data → candidate for C++.
- Everything else stays in TypeScript, because iteration speed is also a feature.
The JS thread is a shared resource. The question is never "is this function slow?" — it's "what else can't happen while this function runs?"
A concrete case: markdown parsing for LLM UIs
If your app renders LLM output or chat, you're parsing markdown constantly — and streaming makes it worse, because each incoming chunk triggers a re-parse exactly when the UI is busiest animating new content. That contention shows up as dropped frames at the moment the app should look most alive.
That's why I built react-native-nitro-markdown:
- parsing runs in C++, off the JS thread, exposed over JSI via Nitro Modules
- the JS side receives a ready AST and just renders
- per-chunk re-parses during streaming stay cheap
The library is open source — issues and PRs welcome.
Why Nitro Modules specifically
Nitro Modules give you the modern version of the native module story:
- 01JSI, not the bridge — calls are effectively function calls, not serialized messages, so fine-grained APIs stay viable.
- 02Typed codegen — the TypeScript interface and the C++ implementation can't drift apart silently.
- 03Swift/Kotlin/C++ freedom — you pick the language per module; for pure computation, C++ means one implementation for both platforms.
What I'd tell a team considering this
- Measure first. Profile the JS thread under real usage. If your bottleneck is render count, fix that in React first — C++ won't save you from re-rendering a list.
- Move the smallest thing that works. A parser, a diff, a crypto routine. Not "the business logic."
- Keep the boundary boring. Plain data in, plain data out. The moment your native module holds UI state, you've built a second app.
- Budget for ownership. A C++ module is a product: it needs CI, tests on both platforms, and someone who isn't afraid of it.
The new architecture didn't make React Native "fast" — it made performance a set of deliberate choices instead of a ceiling. That's a much better deal.