I have been working professionally with React Native for quite some time now. On the side I’ve made a lot of time for Flutter as well. I’ve been using Flutter since before they even had web support in beta, so I would say I had a chance to really experience how it feels to use it.

TL; DR

Flutter is great, but not as wide-spread as React Native.

Language

First of all I have to say that if you use Javascript without Typescript, this is not going to be a fun transition for you.

Dart is relatively new compared to Javascript, but it’s a very strong language and I can easily say that it’s safer to code with it. You can always work-around things even with Typescript (not even getting into the weird parts of Javascript), but Dart pushes you into writing better code. If you are ever unsure of what to do there is perfect documentation for almost everything here. It’s an amazing read.

If you are willing to get your hands dirty with some object oriented concepts and you prefer a language that works without weird quirks, then Dart is an amazing choice. Dart was created thinking it would work everywhere like JS does, but of course it is not even comparable in the means of how wide-spread they are. Dart recently picked-up its pace in improving together with Flutter and it’s already gotten much much better. The null safety update that the Flutter team seemed to be in love with is a proof of this.

At the same time, Typescript is getting amazing updates continuously, it supports almost everything that Dart has if not more, but unfortunately Typescript itself cannot get around the quirks of Javascript.

Gotta give this one to Flutter.

Documentation

Speaking of documentation there is definitely an obvious difference in documentation between Flutter and React Native. The Flutter team completely overdid themselves in this area. Without going to the documentation page and looking things up there you already get a very detailed documentation just by the hover of a mouse. Here’s a small example:

flutter documentation image

And here’s the best out of the box documentation I could find on React Native:

react native documentation image

You can scroll with the one on Flutter, they have other examples and even a youtube video link embedded in the comments (I just didn’t want to add the whole thing here as it is very long). On the other hand this is all React Native gives.

There is literally no discussion on this, Flutter comes out on the very top.

Out of the Box Support

The supported capabilities that come out of the box with a framework is quite important, so that we don’t have to depend on third party libraries that constantly get discontinued and deprecated.

In the year 2021 a new project on React Native comes with Java and Objective-C on the native side. Thankfully Java is easily convertible to Kotlin, but it’s not as easy with Objective-C and Swift. You have to also create bridging headers to connect the two languages if you want, which creates chaos in the native part. On the other hand Flutter comes with Kotlin and Swift. That’s it.

Looking at the components and widgets that we get out of the box, there is also a very big difference here. React Native comes with a bunch of components.

There is some unfairness here as almost everything in Flutter works through widgets, but the count of widgets we get is much higher even without the irrelevant stuff. I have created some fully developed applications with Flutter and I very rarely had to go for a work-around compared to React Native.

On top of everything Flutter supports web (even if not that great yet) and desktop builds. I believe this is a very important thing for the future of software development and even though React Native sort of supports these builds with third party libraries it is not even close to where Flutter is currently both with performance and widgets.

The final step here I want to mention is integration testing. One of the best solutions for integration testing on React Native is Detox. Detox is great and all, but it lacks a lot of functionality. Most of the breaking changes, actually breaks things, there is no support for iOS device support and you cannot run these tests on places like Firebase Test Lab, so you have to deal with CI tools.

With Flutter 2 the integration_test package is now inside Flutter SDK, which means it gets full support from the Flutter team and works just perfectly and the set-up takes 5 minutes, which is inevitably longer with Detox. The best part is Firebase Test Lab is supported with these integration tests all you have to do is add a step to your CI build.

I can see absolutely no competition here, this goes to Flutter for me as well.

Ease of Use

Like a cherry on top Flutter comes with code formatting. I can already imagine some people saying “yeah, but I can add it on React Native as well.” Having things out of the box is just easier.

Flutter has a lot of shortcuts that help while writing code and especially when writing the UI. The widgets themselves help a lot with everything related to UI. Even the simplest animation with React Native can seem a bit complicated but Flutter supports widgets like AnimatedOpacity. Meanwhile you have to go through this with React Native.

Flutter

AnimatedOpacity(
  opacity: opacityLevel,
  duration: const Duration(seconds: 3),
  child: const FlutterLogo(),
),

React Native

const fadeAnim = useRef(new Animated.Value(0)).current

React.useEffect(() => {
  Animated.timing(
    fadeAnim,
    {
      toValue: 1,
      duration: 10000,
    }
  ).start();
}, [fadeAnim])

return (
  <Animated.View
    style={{
      ...props.style,
      opacity: fadeAnim,
    }}
  >
    {props.children}
  </Animated.View>
);

Let’s also talk about the elephant in the room. Metro server. If you say you like the metro server, you must be lying. On Flutter you open your project and press one button and everything just runs, simple as that, this alone is enough for me for ease of use.

Performance

Last but not least or maybe the most important subject is Performance. Flutter was developed from the ground up taking performance into consideration. When rendering a component React Native goes to the native side and takes the component from there to display it to the user. Flutter instead draws everything itself pixel by pixel, this immediately gives Flutter an advantage.

Ever wondered why none of the big applications with React Native have no capability to rotate a fullscreen gallery? Recently I had first-hand experience with this. React Native simply cannot support this. It’s so slow and buggy that you’d rather just not do it. Out of curiosity I tried the same implementation on Flutter and there was absolutely no performance issues, it worked almost like it was a native implementation.

This may sound like an edge-case but the whole feel of the application is definitely different with Flutter. On React Native the bigger your application gets the considerably worse the performance is, but with Flutter you can take things so much further. Performance medal goes to Flutter as well.

Which One Should You Use?

I am not going to say “there is no clear winner here” like all the other comparison posts. The clear winner is Flutter for me. Although you should be aware that Flutter is still relatively not used that much by companies. This may be changing slowly and Flutter is taking more and more of the market, but they still cannot be compared in this sense as almost everyone still uses React Native for cross-platform mobile development. Flutter is basically an investment for the future.