Editor’s note: This article was updated July 2021 with information about Flutter 2’s web support and an up-to-date comparison for React Native and Flutter. You can learn more about Flutter 2.0 here.
As developers, we are always on the lookout for tools that would allow us to save time and effort. We want to be able to write code and run it everywhere. With React Native and Flutter, this dream is slowly turning into reality. Because now, not only can we run apps on both Android and iOS, we can run them on the web and even desktop as well.
In this article, we’re going to compare each platform. Then we’re going to zoom in on their web capabilities to see if they are good enough to be used in production. Lastly, we’ll look at the pros and cons of each platform. After reading this article, you’ll be able to decide which one to use on your next project.
React Native vs. Flutter: Comparing the underlying platforms
For us to effectively judge React Native Web and Flutter for web, it’s important that we first compare the underlying platform. We have to consider not just the web capabilities, but also the overall platform experience.
We’ll use the following criteria as the point of comparison:
- Beginner friendliness
- Plugin support
- Developer productivity
- App performance
- Web support
- Testing and deployment
How quickly can a beginner go from zero knowledge of the platform to a fully functioning app?
In React Native, it’s a multi-step process:
- Install Node.js
- Install Git
- Install Watchman (for MacOS users)
- Install Expo CLI
- Generate a new project
- Install Expo client on your mobile device
- Run the project
There’s one extra step required to run it on the browser, but that’s negligible because it’s only a command to install the web dependencies.
The steps mentioned above are from the quick start guide. You’ll need to invest more time when setting up your machine if you go the CLI route, though that’s something a beginner rarely needs to do since most of the native APIs are already implemented in Expo.
On the other hand, Flutter’s development setup can be summarized with the following steps:
- Download the Flutter SDK
- Install the prerequisite developer tools (e.g. curl, zip, git)
- Add the Flutter SDK to your system path
- Install Android Studio and Xcode
- Configure XCode command line tools (for MacOS)
- Generate a new project
- Run the project
For the web setup, there are a few additional steps you need to go through.
It looks pretty straightforward, but it can be pretty daunting for a complete beginner with little to no experience of the command line and no understanding of how to install different tools.
The community is another big factor to consider when choosing a platform. This community is the culmination of libraries and plugins, tutorials, forum/Stack Overflow questions, and GitHub issues that are out there.
React Native has more than a two-year head start, but that doesn’t necessarily mean it’s more popular. Flutter has 125k stars on GitHub while React Native sits around 97k. It looks like they’re receiving similar use: both have around 100k questions on Stack Overflow.
In terms of actual usage, according to the Stack Overflow developer survey for 2021, about 15 percent of all respondents are using React Native while about 14 percent are using Flutter.
Web developers are a spoiled bunch. Almost all of the functionality we’re ever gonna need in building modern web applications already has a corresponding library that implements it. All we have to do is learn its API and we’re good to go.
Flutter has a pretty decent plugin system that implements most of the functionality that is commonly used in mobile apps (e.g., social login, Google Maps).
React Native wins this because we can use almost any npm module (except for those node modules with native dependencies).
Another important factor when it comes to deciding which tool to use is developer productivity. This can mean a lot of things, so we’re going to break it down into the following:
- Programming language
- Code structure
- Developer tooling
- UI components
- Native API access
Most people coming to explore solutions for building cross-platform apps using a single codebase are web developers. We want to reuse our existing knowledge of the web ecosystem to build mobile and desktop apps. This means that React Native is a more viable option for us since we practically don’t have to learn anything else to build apps using React Native.
Being able to find the things you’re looking for in a relatively short time and immediately grasp the information is another determinant of developer productivity.
Flutter’s documentation is more organized and more detailed than React Native. But when it comes to beginners, it can be pretty overwhelming to be greeted by tons of links. I like the simplicity of React Native’s documentation.
That said, we don’t stay a beginner forever. Once we gain more experience and get used to where things can be found, then it becomes easier. This is where Flutter’s documentation outshines React Native. Furthermore, React Native relies on a lot of community-written libraries, so its documentation is very fragmented. Meanwhile, Flutter has everything in one place.
As a new developer coming into an existing project, how easy is it to make sense of the way the code is organized?
In React Native, you can pretty much have any structure you want. Usually, it’s dependent on the size of the project and the various tools and libraries that your team has adopted. For example, using Redux will force you into a specific kind of structure since you will have reducers, actions, etc.
The situation is the same in Flutter; you can organize your code any way you want. But since navigation and state management are already baked into the framework, code organization can get more opinionated as well.
Hot reload is one of those things that can get annoying if a platform doesn’t support it. Being able to modify your code and see the changes on the fly as you save is a big productivity booster (especially on a dual-monitor setup).
Both React Native and Flutter support this feature, though it’s faster in Flutter if you compare it with Expo. There’s just a tiny bit of difference when compared to the CLI route for React Native.
Another important thing to consider is the debugging experience. In React Native, error messages can be pretty hard to grasp. While in Flutter, due to Dart being a statically typed language, the error messages it shows tend to be more meaningful.
React Native components translate to native UI components, so it has the same look and feel as a native app.
On the other hand, Flutter paints the UI elements using a rendering engine. It’s responsible for creating all the basic functions of each of the widgets. This means that there’s a constant effort on Flutter’s development to match the native UI behavior whenever there’s an update to the respective platform.
React Native only provides a few basic components. Though there are various UI kits available, it still cannot beat the widget collection that’s built into Flutter. The only downside with Flutter is that it has more widgets available for Android compared to iOS.
Native API access
Both React Native and Flutter support native APIs for commonly used features such as image picker and geolocation. If you need a native functionality that’s not available yet, you can always write custom platform-specific code or create your own native module.
App performance is difficult to judge because it purely depends on what type of app you’re going to build. If your app doesn’t require complex layouts, transitions, and passing data to and from the native side, then you can choose either of the platforms.
Both React Native and Flutter have web support, the former being more of a community-led effort, while the latter is led by the Flutter team.
Web support for React Native is more mature than in Flutter. Web support can be added to existing React Native projects and Flutter projects, though they’re not really comparable. React Native Web compiles to actual HTML elements while Flutter uses the Canvas.
We’ll dive more deeply into web support for each platform later on in this article.
Testing and deployment
Does the platform support automated testing and deployment (provisioning, continuous integration, and deployment)? This can be optional for smaller projects, but crucial for larger ones. It helps us prevent bugs in our apps and not get bogged down by the manual deployment process.
At the time of writing this article, React Native doesn’t have testing and deployment tools baked into it. Just like for everything else, it relies on the tools built by the community. For testing React Native, we have the React Native Testing Library, Jest, and Detox.
Flutter web overview
Flutter web works by using web renderers. Simply put, they’re used for rendering a Flutter app on the web. Flutter uses two renderers: the HTML renderer and the CanvasKit renderer. The former uses HTML, CSS, and the Canvas API to produce pages. The latter is basically Skia for the web using WebAssembly and WebGL.
The main advantage of the HTML renderer is its compact size, though its disadvantage is its performance.
On the other hand, CanvasKit offers great performance but it has a poor startup time. This is mainly due to the additional 2Mb download size compared to the HTML renderer.
Users have access to widgets available for mobile. But developers have to consider making their apps responsive. Therefore they have to use widgets and classes such as LayoutBuilder or MediaQuery so that their apps will look great for whichever platform the user is using.
When it comes to plugins, not all of them have web implementation (e.g., ARCore, Filesystem access). In pub.dev, you can filter the results to only show the plugins that are available for the web.
Why is Flutter web good?
- It’s stable and production-ready
- The feature set is complete and enables developers to build rich, interactive web experiences
- Access to the same widgets that are available for Flutter for mobile
- Full access to all existing Dart libraries that run on the web
- Integration with IDEs and text editors (IntelliJ, VS Code)
Why is Flutter web bad?
- Large download size if you use CanvasKit as the renderer
- Not SEO friendly
- Currently more suited for progressive web apps and games rather than typical websites
React Native for Web overview
React Native for Web is an open-source project by Nicolas Gallagher. React Native for Web makes it possible for developers to use React Native components and APIs on the web. The clear advantage of this is that it allows for code-sharing between multiple platforms, so you only have to write mostly single code and be able to run it everywhere.
Perhaps one of the first questions that comes to mind when you hear about React Native for Web is why not just use React? The answer to that is code sharing. If you use React, you can’t really take advantage of the tools that React Native has to offer. And you’ll be coding the same functionality twice.
Do note that not all of the native components and APIs are available to the web. This is because not all of them have an equivalent web API. The main thing that React Native for Web does is to map out the web equivalent for each of the React Native components and API. So the
<View> component becomes a
<Image> component becomes
<img>, and so on.
The second question that might come to mind is what’s the difference between React Native for Web and Expo Web? How do I know which one to use? Well, just like how there’s the standard CLI route for React Native projects, there’s also the quick start route, which is Expo.
Expo Web is just a nice addition that you get when you’re already building your projects with Expo. So if you already have an existing project, the main deciding point is whether you’re building your project in the standard CLI way or Expo. However, if your project is new, it will solely depend on what your project is all about. If you think you’re going to need a lot of third-party libraries with native dependencies, then you’re better off sticking to the standard React Native CLI. Otherwise, there’s really no reason not to use Expo since it just makes things that much easier for you.
Developers who plan to use React Native for Web have to worry about the following problems:
- Just like how there are platform differences between Android and iOS, the same is also true for the web. This means that your existing React Native code won’t immediately run on the web just by using React Native for Web. You still have to do a lot of platform detection and code modification. This is especially true for things like the file system.
- Not all APIs that are available in React Native are available in the browser. This means that if you have an existing React Native app, you either have to re-implement the functionality on your own or simply not support it at all when on the web. An example of this API issue is the Image Editor.
- Not all components that are built into React Native or Expo work on the web. An example of this is the Modal component. Sometimes there’s another developer who would publish their own version of the component that can run on the web, but in cases where that’s not available, then you have to build your own component. The same thing is true for libraries; the authors will have to write their own implementation for the web.
Why is React Native for Web good?
- Just like React Native, React Native for Web includes tools that allow developers to build accessible apps. This is provided through accessibility props such as
- Allows for executing web-specific code via platform detection. We can’t expect all the APIs to work, thus it’s very important to detect the platform so that you only execute code that works for the current platform
- Support for server-side rendering. You can use
AppRegistryto hard-code the HTML document string to be used for rendering the app
- Expo Web serves as a wrapper for React Native Web so you can start a single Expo project that can be run on Android, iOS, web, and even desktop (through Electron)
- Expo web supports progressive web apps
Why is React Native for Web bad?
- At the time of writing this article, React Native for Web is still not production-ready
- React Native packages with native dependencies cannot be run on the web. If you’re relying on third-party packages with native dependencies (Swift/Objective-C or Java/Kotlin code), then those won’t work on the web
- React Native packages with no native dependencies cannot be expected to work 100 percent either. This is especially true if it involves animations, transitions, gestures, the keyboard, and lists
Flutter pros and cons
To wrap up, let’s take a look at what makes each platform great and not so great. First up is Flutter. Note that we’re not going to go over the good and bad points that are similar between the two platforms. Instead, these points can either make you “yay” or “nay” when it comes to choosing the platform that’s best for you:
Why is Flutter good?
- Performance is very close to native because your code compiles to native code
- Lots of inbuilt widgets for both Material Design and Cupertino
- Inbuilt testing support
- Detailed and well-organized documentation
- Error messages are more meaningful because Dart is strongly typed
Why is Flutter bad?
- Slightly steep learning curve
React Native pros and cons
Let’s now go over the pros and cons for React Native:
Why is React Native good?
Why is React Native bad?
- Slower hot reloading on Expo when compared to a standard React Native project
- Documentation is sparse and not very detailed
- Limited native UI components
- It doesn’t have an official testing utility
Which is better: Flutter web or React Native for Web?
On the other hand, Flutter web is also production-ready depending on your needs. The main issue with it is really the performance. They have solved it using CanvasKit, but the user will have to wait even more to download the necessary scripts.
Overall, it’s an exciting time to be a developer because we can now reach more platforms than ever. All of that without leaving the comfort of the tools we know and love.
LogRocket: Instantly recreate issues in your React Native apps.
LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your React Native apps — try LogRocket for free.