Modern mobile application development teams tend to use mobile app-specific frameworks to build their apps for several advantageous reasons: a single codebase for developing Android and iOS apps; developer-friendly tools; platform-independent, abstract native APIs; and community support.
There are two different mobile framework types: hybrid and native.
Hybrid mobile frameworks, like Ionic and Apache Cordova (formerly PhoneGap), let developers build hybrid mobile apps by loading web resources to a native webview component. On the other hand, native mobile frameworks like Flutter and Kivy let developers build native mobile apps by offering a platform-agnostic UI toolkit. Meanwhile, React Native offers different a way to build native apps with a headless-webview concept.
In this article, I will provide a detailed and practical comparison between Flutter and Ionic for selecting the best framework to build your next mobile app.
Flutter is a cross-platform software development kit developed by Google. The Flutter framework lets developers build apps in Dart, using a widgets-tree-based layout, and was initially a cross-platform mobile application development framework that produced application packages for Android and iOS. More recently, the Flutter team extended the framework by supporting desktop (Linux, macOS, Windows, and Fuchsia) and web targets.
Flutter doesn’t use web-based or platform-specific UI elements. It uses an inbuilt UI toolkit and renders graphics via the Skia cross-platform graphics library.
Ionic is a hybrid mobile application development framework developed by Max Lynch and Ben Sperry. Ionic was initially built on top of the Apache Cordova framework, but the Ionic team made Capacitor.js as a replacement for the Apache Cordova foundation layer.
Ionic doesn’t use native platform-specific UI elements. It uses native-like, web component-based UI elements and renders them in a webview component. Ionic lets developers build mobile apps with Angular, React, Vue.js, and Stencil frontend libraries.
Ionic officially supports Android, iOS, and web targets. The developer community also created Electron-based desktop app generation support.
Let’s look at the impressive usage statistics of Flutter and Ionic.
Apps built with framework
Popularity and market share statistics typically give us a sense of developers’ awareness of the frameworks, the success of each framework’s marketing strategy, and developers’ satisfaction level with each specific framework. These statistics data won’t show us clear user-experience factors, performance factors, and features for technical decision-making in our projects. For example, the most popular framework might not solve your primary technical requirement.
For that, let’s move on to the next section, comparing each framework’s architecture and how it’s suited to different environments.
Learning framework internals is undoubtedly the best technical decision-making activity you can do before selecting a framework for your next mobile app. A framework’s internal architecture gives us a clean, transparent overview of each framework product’s feasibility and future.
Flutter has three main layers:
Remember the following important points about Flutter from the above technical review:
The Ionic framework has three main layers:
Remember the following important points about Ionic from the above technical review:
The development workflow is a crucial comparison factor — because it directly affects developer productivity.
Now that we know about each framework’s primary building blocks, let’s develop a simple app from each environmental setup and run it on a real mobile device to study the learning curve, developer tools, and developer environment.
If you’ve developed a Flutter application before, you can skip to the end of the Flutter tutorial section.
Flutter application development requires setting up two components: the Flutter CLI and the platform-specific SDK. The platform-specific SDK installation is required only for mobile platforms because most desktop platforms already include the required developer libraries by default.
First, install the Flutter CLI according to the official guide. If you are on Linux, you can use the following Snapcraft command (run with
sudo) to install it quickly.
>snap install flutter --classic
Next, you have to set up mobile SDK tools. If you plan to test the app on an Android device, you can use the following command to install Android Studio.
snap install android-studio --classic
The Flutter CLI provides a helpful diagnostic command called
doctor to find configuration issues. You can start creating a Flutter app if the
flutter doctor command doesn’t show any critical errors, as shown below.
You can create a new Flutter app with the following command:
flutter create myapp
The above command will generate a minimal sample Flutter application very fast, since there are no external dependencies like Node.js modules.
You can run the application on an Android device with the following command:
cd myapp flutter run
The above command creates a debug build of the Android embedder app with Flutter hot-reloading support and runs on the connected physical device or virtual device.
You can browse the source code of the sample application from the
lib/main.dart file. As you may have already noticed, Flutter comes with a widgets-tree-based layout system that other popular cross-platform mobile frameworks don’t use. The widgets-tree-based layout offers a friendly development environment for developers who have previously worked in native application development, but it’s a new and somewhat confusing concept for frontend and web developers.
Even though Dart is a new development technology for most developers, developers can still use the familiar, generic project architecture patterns to build large-scale apps. For example, we can structure our Flutter codebases with the repository pattern, MVC pattern, services, DAO pattern, and state management patterns, like BLoC, by also decomposing large UI into multiple widgets.
The Flutter CLI offers the
build command to produce application packages. Flutter generates ahead-of-time (AOT) compiled Dart code segments for faster application startup with production builds.
Let’s generate an APK of the example application. You can generate a fat APK for multiple CPU architectures with the following command:
flutter build apk --release
The above command generates a 15.8MB-sized, single APK. However, we can generate an APK for a specific CPU architecture with the following command:
flutter build apk --split-per-abi
The above command generates a 5.2MB-sized, CPU-dependent APK for my arm64-v8a Android device, along with two other APKs for different CPU architectures. Flutter offers this CLI feature to reduce the application package, since it uses Android NDK-generated, CPU-dependent dynamic libraries.
Remember the following points from the above practical review of the Flutter application development workflow:
If you’ve developed an Ionic application before, you can skip to the end of the Ionic tutorial section.
Ionic application development requires setting up three software components:
First, make sure that you already have the latest Node.js LTS version installed. Next, install the Ionic CLI program with the following command.
npm i -g @ionic/cli
The above command activates the
ionic command globally; you can verify it by entering
ionic on your terminal.
You can create a new Ionic app with the following command.
ionic start myapp
The above command displays a project creation wizard and asks you to choose a frontend library and app template. I selected React and the blank template for this example. Project creation takes some time compared to the Flutter CLI because we have to install the Node.js modules.
You can run the Ionic application on an Android device with the following command.
ionic capacitor run android
The above command triggers a React production build and won’t enable the hot-reloading (HMR) feature. However, the Ionic CLI provides the following command to activate hot-reloading with the frontend framework developer tools:
ionic capacitor run android -l --host=<your_ip_address>
Note that you need to connect both your mobile device and your computer to the same network before executing this command. The Ionic documentation suggests previewing the application on the web browser with the
ionic serve command before previewing with real devices or emulators.
Ionic renders web-based application UI via platform-specific webview components. Therefore, it lets you use the most popular frontend frameworks like React, Angular, and Vue to develop UI components.
Every popular frontend framework typically comes with XML-like templating syntax, which means frontend developers don’t need to learn a special layout syntax like Flutter’s widgets tree.
The Ionic framework and Capacitor.js consist of loosely-coupled framework components. Therefore, you can easily use only Capacitor and turn your existing web app or PWA into a hybrid mobile application without Ionic components. As in Flutter, you can use any architectural pattern you want to organize your code for large-scale applications.
Ionic also has a
build command, but it doesn’t directly generate release packages for Capacitor-based projects. The
ionic build command packs web resources to the host app and opens the mobile development IDE for manually compiling mobile platform binaries.
For example, the following command updates the host app with web resources and opens Android Studio automatically.
Android Studio generated a 3.6MB-sized APK with the Gradle release build configuration.
The Ionic team is planning to extend the CLI to generate release binaries, as Flutter does via this GitHub issue.
Remember the following points from the above practical review of the Ionic application development workflow.
Now that we have an idea of how each framework supports developers with tooling, let’s factor in UX. Developers create apps for end-users — so user experience factors also help mobile applications to become successful.
Flutter doesn’t use UI elements from the operating system’s inbuilt libraries — it uses consistent native UI elements on every platform—but you can apply the Cupertino UI theme on iOS to make iOS-like UI elements. Flutter UI’s main goal is to provide a consistent user experience across different operating systems.
Flutter renders widgets so efficiently, even on low-end devices, due to the AOT compilation and high-performance Skia library.
Ionic provides pre-built, native-like UI elements with the web components technology. Your hybrid Ionic app will render different CSS styles automatically on each platform to match the native UI style. For example, the Ionic button component will look like an Android button on Android devices, and look like an iOS button on Apple devices.
Ionic’s UI rendering performance depends on the platform’s specific webview HTML rendering performance. Users may sense the app is a web application if they run a complex HTML screen on low-end devices due to the slow HTML rendering and delay in web resource loading.
Neither Flutter nor Ionic directly calls native platform SDKs. Instead, each framework runtime uses different approaches to communicate with native SDKs. Let’s discuss how the framework affects performance and resources usage.
Flutter uses a binary messaging protocol called platform channels to communicate with native SDKs, so it offers near-native performance while dealing with platform APIs. The AOT-compiled binary also removes Dart code parsing and compilation steps for production apps decreasing the TTI (Time-To-Interactive) factor drastically.
We have to think twice if we choose Ionic to write a mobile app that often calls native SDKs. However, these performance drawbacks of the Ionic framework only happen with low-end or embedded devices because modern mobile devices typically come with powerful hardware.
The bundle size usually depends on application resources regardless of the framework in most cases. However, Ionic offers the lightest framework binary, since it just uses a native splash screen and webview component in the host app. By comparison, Flutter’s framework binary is somewhat larger, due to the platform-dependent Flutter engine libraries.
Flutter officially supports Linux, macOS, Windows, and Fuchsia desktop platforms. Therefore, you can turn your Flutter app into a desktop app without third-party tools or frameworks. Try it out and see how easy it is to run the above sample Flutter application as a native desktop app.
We need to enable desktop support and enter
flutter run to open the desktop app.
flutter config --enable-linux-desktop flutter create --platforms=linux . flutter run -d linux
The above commands build and run the Flutter app as a native GTK-windowed application, as shown below.
Ionic doesn’t officially support desktop platforms, but the Ionic community created a project to turn Ionic apps into hybrid desktop apps with the Electron framework. This desktop app-generation workflow is also as easy as Flutter’s desktop app-generation support.
You can run your Ionic app as a hybrid desktop with the following commands. These commands will work faster than the Flutter desktop app execution commands because Electron typically comes with pre-built binaries.
npm i @capacitor-community/electron npx cap add @capacitor-community/electron npx cap open @capacitor-community/electron
The above commands open the Ionic app as an Electron desktop app, as shown below.
You don’t need to put in any extra effort to convert Ionic apps to web apps, since Ionic apps are already web apps. For example, if you use React to build your Ionic app, you can trigger a production build and obtain a deployable web app. Ionic components will work on any web browser without any performance issue because they are HTML elements.
Flutter also supports web application generation via two different renderers: HTML renderer and CanvasKit. The HTML renderer renders the Flutter app on a browser with a mixture of HTML elements and canvas elements. It has a smaller download size than the CanvasKit.
The CanvasKit renderer tries to offer a native-like performance on the browser, but has a somewhat large download size. However, both web renderers use canvas elements instead of native HTML elements.
We’ve discussed framework internals, development workflows, desktop support, web support, user experience, and the performance of both frameworks. Now, we can summarize all comparison data into one table for studying the pros and cons.
But first, you need to understand that no mobile framework will produce technically great apps as native apps — we use frameworks mainly to reduce development time.
Flutter and Ionic both offer impressive features, but also come with several drawbacks, so we need to carefully pick a framework based on our project’s primary requirements.
Look at the summarized pros and cons of Flutter and Ionic.
We can decide when to use Flutter and Ionic based on the above pros and cons. Carefully choose the most suitable framework based on your requirements , rather than just considering the current trends.
Use Flutter if:
Use Ionic if:
In this article, we compared Flutter and Ionic frameworks from various perspectives. Frameworks are changing rapidly, so a specific framework can introduce a feature at any time to make the particular development workflow even more productive.
The underlying architecture says a lot more about a framework’s feasibility and stability than the way in which a specific framework product is advertised to the developers. That’s why we discussed the internals of each framework before proceeding with the evaluation.
Both Flutter and Ionic are good mobile frameworks and loved by millions, but Flutter undoubtedly wins from the performance perspective, while Ionic is recognized as the most productive tool for web developers to build hybrid mobile apps.
Choose a framework by carefully studying your requirements — there is no easy way to switch from Ionic to Flutter or Flutter to Ionic, rather than rewriting the entire app.
Install LogRocket via npm or script tag.
LogRocket.init() must be called client-side, not
ElectricSQL is a cool piece of software with immense potential. It gives developers the ability to build a true local-first application.
Leptos is an amazing Rust web frontend framework that makes it easier to build scalable, performant apps with beautiful, declarative UIs.
We spoke with Dom about his approach to balancing innovation with handling tech debt and to learn how he stays current with technology.