Fintech’s Multi-Platform Dilemma: Flutter or React Native?
Currently, I work for a digital payment company in Indonesia called YourPay, a mobile banking service that helps Indonesian Migrant Workers and their families conduct transactions overseas.
YourPay is currently available on a single platform, Android, with the app written using the Native Android framework. Recently, the company decided to expand to iOS. Instead of maintaining separate native frameworks for iOS and Android with two distinct teams, the company chose to move towards a multi-platform/hybrid approach.
Flutter vs React Native
Switching to a multi-platform framework was a significant decision. We needed to ensure that we could deliver our product quickly and efficiently while considering key factors like performance, security, and scalability. Among the available frameworks, React Native and Flutter are the top contenders in the multi-platform application space.
Deciding which framework to use was a challenging task for me as a Frontend Lead, especially during my first week at the company. I had to weigh many factors before arriving at the “best” decision, considering both technical and business aspects.
Security
Security was our top priority since our company relies heavily on user trust. Ensuring that our users are fully protected is critical. In this regard, Flutter stood out as the better option.
React Native
React Native consists of two main components: JavaScript and Native. The application’s business logic resides on the JavaScript side, within a file known as main.jsbundle
, which can be "easily" reverse-engineered.
This vulnerability could allow someone to manipulate the app's logic, potentially leading to malicious behavior, especially in an app that handles large transactions for users who may not be tech-savvy. You can see how this guy did, he could manipulate the javascript part to alter the logic and unlocking unexpected behaviour of the app.
Even with the introduction of Hermes — a JavaScript engine optimized for React Native — JavaScript can still be decompiled using tools that are readily available, posing a security risk. You can see the detailed step how to do it in this article.
Flutter
Flutter, on the other hand, is “safer” because it compiles directly to native code. While no system is entirely secure, Flutter’s approach makes it more challenging to reverse-engineer. Unlike React Native, which relies on a bridge to communicate between JavaScript and native code, Flutter compiles directly to native code, reducing the risk of tampering.
While Flutter isn’t entirely immune to reverse engineering, the process is more complex and constrained compared to React Native. You can take a look to these two tools that built specifically to help reverse engineers to do their work:
Despite Flutter’s advantages in security, it doesn’t make Flutter invulnerable to attacks. Similarly, React Native can be made more secure through various methods. However, in this context, I prefer Flutter due to its stronger security features.
Accessability
Accessibility was our second most important concern. Some of our users are not tech-savvy and use low-end devices, starting from Android 5.1.1. In this area, Flutter was the clear winner.
React Native
The latest React Native version requires a minimum Android SDK version of 23 (Android 6.0). Choosing React Native would mean leaving behind users still on Android 5.x.x, which isn’t an option given that many of them still rely on our app for essential transactions.
Flutter
Flutter, however, still supports Android Lollipop (API 21–5.x.x), ensuring that all of our customers can continue to access and use our app without any issues.
Performance
Performance is a critical factor for us, as we prioritize functionality over aesthetics or other non-essential features. Our goal is to create a simple, user-friendly app that meets our customers' needs efficiently. In terms of performance, Flutter emerged as the winner.
React Native
React Native is having an architecture where there are two main sides: Javascript side and Native side and there is a bridge connecting those two sides.
React Native uses bridge to connect Javascript that contains most of the business logics with native modules. The JavaScript code runs in a separate thread and communicates with the native side, which can introduce latency, especially in complex applications with heavy UI interactions.
React Native can also achieve smooth animations, but it may struggle with performance in more complex scenarios due to the overhead of the JavaScript bridge. This can result in dropped frames and a less smooth user experience.
How about the latest improvements on the “bridge”? Yeah, there should be a lot of improvements in the future, one of them included to current latest version right now by introducing JSI and there might be more improvements coming in the next version of React Native.
Flutter
Flutter, in contrast, uses the Skia graphics engine to render UI directly to the canvas, bypassing native UI components. This approach allows Flutter to deliver near-native performance, with smooth animations at 60 FPS or even 120 FPS on devices that support higher refresh rates.
Flutter’s direct rendering approach also reduces overhead, making it the better option in terms of startup time, battery consumption, and memory usage.
Team
Our existing mobile app team has a strong background in Native Development (Android and iOS), with extensive experience in Java, Kotlin, and Swift — languages that are object-oriented and strongly-typed by default. For this reason, Flutter was the better choice.
React Native
React Native’s business logic is written in JavaScript or TypeScript. While it’s possible to write on the Native side using Native Modules, most of the development time would be spent on JavaScript or TypeScript.
Transitioning to functional programming with a language as flexible as JavaScript was challenging for our team, who found adapting to TypeScript difficult given their extensive background in Kotlin, Java, and Swift.
Flutter
Flutter, on the other hand, uses Dart — a language less widely known than JavaScript but similar in syntax to Java, C#, or Swift.
This similarity made Dart easier for our team to learn, as they were already familiar with object-oriented programming and strong typing. Dart’s structure and focus on object-oriented programming provided a smoother transition for our team.
Scalability
Our company is currently stable in terms of growth — slow but steady. While we’ve achieved product-market fit, we’re focused on profitability and sustainability rather than “hyper-growth”. However, we have exciting and ambitious projects for the future, and scalability is essential to our long-term vision. In this aspect, Flutter proved to be the better choice.
React Native
Having worked on several projects using React and React Native with TypeScript, I’ve found it challenging to keep React code clean as projects grow in complexity. JavaScript’s flexibility, while beneficial in smaller projects, can lead to maintainability challenges in larger applications, even with TypeScript.
Flutter
Flutter, with Dart, promotes maintainable and readable code, which is crucial as projects become more complex. Dart’s strong typing and object-oriented features make it well-suited for building scalable applications.
Although JavaScript is more popular and widely used in web development, I believe learning Dart isn’t difficult, especially for developers familiar with languages like Java, C#, and Swift.
Conclusion
Choosing the right multi-platform framework is not easy. There’s no “best” framework that fits every situation. It all depends on the specific needs, context, and conditions of your project. I hope this blog post has provided you with insights to make better decisions when choosing a multi-platform framework.
Don’t forget to clap, share, and drop your comments below! If you’d like more personal and interesting posts, please follow my Substack channel. Thank you!