mobileflutter
Flutter or React Native: what we use and why
· 6 min read
The question comes up constantly when people ask about the Lima stack: why Flutter and not React Native? React Native has gotten genuinely good. The new architecture (JSI, Fabric) fixed the bridge latency that used to be the main argument against it. The JavaScript bridge is no longer the bottleneck it was in 2020. So the choice is less obvious than it looks.
Here’s where we landed and why.
Flutter owns the pixels
Flutter renders everything with its own engine (Impeller, now the default on both iOS and Android). React Native renders native components, which means platform-specific behavior, platform-specific quirks, and occasionally visual differences between iOS 17 and Android 14 that you didn’t ask for.
For Lima’s habit grid: 84 squares per user, specific gap, specific corner radius, specific animation. Impeller just draws it. On every device, in every OS version. There’s no negotiation with UIKit or the Android View system. What you build is what ships.
That property compounds. Every custom component, every animation, every transition: the output is predictable. When something breaks, you’re looking at your own code, not a platform rendering difference that exists in one OS version and not another.
Dart is not the problem people think it is
The standard objection to Flutter is Dart. Nobody wants to learn another language. That’s real. But Dart is typed, modern, and familiar to anyone who knows TypeScript or Kotlin. The learning curve is steeper than JavaScript but flatter than Swift or full Kotlin with coroutines. Our experience: productive in about a week, comfortable in a month.
React Native’s language advantage is genuine when your team already writes TypeScript. The argument “my web engineers can contribute to mobile” holds up. For Lima, we were building this solo, so the language choice was purely about what would be faster to get right, and Dart with Flutter’s tooling was the answer.
Where React Native actually wins
Brownfield integration. If you’re adding a screen or a feature to an existing native iOS or Android app, React Native drops in more naturally. Flutter can do it, but the setup is more invasive and it shows.
JavaScript ecosystem size. RN has more packages for more niche things, and many of them are more mature. If your specific use case has a JS library that doesn’t have a Flutter equivalent, that gap matters.
Team productivity when the team is JS-native. If you have five TypeScript engineers and a one-month deadline, RN gets you to production faster than asking those engineers to learn Dart while building. Shipping something real is better than building the right stack.
The practical call
Greenfield mobile app, targeting iOS and Android (potentially web later), team open to learning: Flutter. The pixel ownership, the hot reload that actually works reliably, and the web target pay back the Dart learning curve quickly.
Existing JS team, brownfield integration, time pressure: React Native. The new architecture is solid, the ecosystem is rich, and if your engineers are already there you’ll ship faster.
Lima on Flutter meant one codebase for iOS, Android, and web. 25,000 users across platforms, no rendering bugs we didn’t introduce ourselves. That’s the case it made for us.
The same reasoning applies when we build for clients. Greenfield mobile products we build in Flutter. Projects where the client has an existing JS team and needs us to add mobile coverage, we evaluate React Native seriously. The framework follows the problem.
More from building Lima: the ETag caching bug that took us three sessions to trace, and the Brazilian ninth digit problem that silently broke WhatsApp matching for some users.