React Native is a framework for building cross-platform applications with one codebase. But every team will eventually face a moment where using third-party packages cannot deliver the full experience—maybe the package you decided to implement has limited access to native platform APIs, does not allow full control, or has limited customizations that prevent you from meeting design requirements.
At those moments, you’ve got two options:
This is when you realize: stick with convenience, or take control by building it yourself. To see why this trade-off matters, let’s step back and understand what native modules actually are.
Native modules act as the bridge between React Native’s JavaScript layer and the platform APIs in Swift, Objective-C, Java, or Kotlin. Once registered, they work just like any JS module, but under the hood, they’re calling native code.
Most of the time, developers shortcut this by implementing a library from the community (which wraps the native layer for them). That works great until you run into real-world requirements.
Let’s imagine Speakic: a language learning app with a “Hold to Speak” button so users can practice pronunciation and listen to phrases out loud.
The fastest way to build it? Install react-native-tts, @react-native-voice/voice, and call:
import Tts from 'react-native-tts';
import Voice from "@react-native-voice/voice";
export default function HomeScreen() {
// Rest of the code...
const startListening = async () => {
...
await Voice.start("en-US")
...
}
const stopListening = async () => {
...
await Voice.stop()
...
}
const speak = (item: string) => {
...
Tts.speak(item)
...
}
// Rest of the code...
}
✅ Achieving cross-platform pronunciation, with almost no effort.
But the trade-offs show when third-parties begin causing problems:
Midway through 2023, developers ran into an issue with the dependency react-native-voice:
The community reported the error:
While the community shared fixes, the official patch wasn’t merged right away, and developers had to fork the repository and apply the fix manually, or wait until the update was published.
In cases like this, writing your own module makes a big difference.
When you roll your own module (in Swift or Kotlin), you’re in charge of how it behaves. Here’s what that means in practice:
| What you gain | What it costs |
|---|---|
| Full control over behavior, even after OS updates | Extra dev effort to write and maintain |
| Direct access to platform APIs | Need to keep up with OS changes |
| Room for performance tweaks | Complexity of bridging code |
| Fewer third-party dependencies | Long-term maintenance responsibility |
Think of it this way: would you rather fix those issues yourself today, or wait for someone else’s library to patch it later?
💡 Speakic’s speech features run on a small custom native bridge (Kotlin + Swift) we wrote to connect React Native with the system APIs. If you’d like to peek at the full implementation, the reference code is available here: 👉 check out the repo
Not every feature needs a custom build. Community modules can save weeks of work when:
It is all about balance: Use third-party libraries for standard features and create your own when the functionality you are building is the core of your product or when you need full control.
Let’s break it down separately:
Native modules speed up experimentation.
One thing to highlight about native modules is how they speed up experimentation. If Apple or Google release a new API, you do not have to wait months for the ecosystem to catch up, you can wire it yourself and ship a prototype next week.
For a product team, that’s a huge competitive edge. It means you’re not following trends, you’re testing them before others can. This accelerates innovation cycles and lets products differentiate faster.
For teams building hybrid apps, being able to create native modules gives them a competitive advantage.
Third-party modules make life easier, If your app needs a date picker, there’s no reason to reinvent it. The community already maintains great ones that work across iOS and Android.
But the real power of React Native shines when you build your own bridge to native APIs. Owning them means owning the experience end-to-end. That’s what makes hybrid apps truly flexible: the speed of React Native plus the control of native.
That’s what makes hybrid apps truly flexible, the speed of React Native combined with the control of native.
Sooner or later, you’ll need something that isn’t on npm or yarn, and the teams that can build it themselves have a significant advantage.