Flutter or native: how to choose for your app

Youssef MohamedUpdated 13 min read

The short answer

For most business apps, such as listings, booking, delivery, content, shopping and customer portals, Flutter is the practical choice. You write the app once in Dart, and it ships to the App Store and Google Play as a real compiled app.

Native development, meaning Swift for iPhone and Kotlin for Android, is the better call when the product is built around one platform's newest features, heavy 3D or augmented reality, deep system integrations, or when you only need one platform.

Most of my mobile work is in Flutter for that reason. 90Plus, a football app with live scores, daily quizzes and predictions, is published on both stores in Arabic and English. Online Ezzay is an Arabic-first delivery app for placing orders and following shipments live. Both are the kind of app Flutter suits: many screens, live data and Arabic layouts.

How Flutter draws the screen

A native iOS app is written in Swift, today mostly with SwiftUI, and uses Apple's own buttons, lists and text fields. A native Android app is written in Kotlin, today mostly with Jetpack Compose, and uses Google's components. That means two apps, two languages, and two teams or one person who knows both well.

Flutter works differently. Your Dart code is compiled ahead of time to machine code for release builds, and Flutter draws every pixel itself with its own rendering engine (Impeller is the default on iOS and Android). It does not wrap the platform's buttons. It ships its own widgets, in a Material style and an iOS-like Cupertino style.

That design is why a Flutter screen looks the same on every phone, and why the same layout code runs on both platforms. It also means Flutter has to keep up with each platform's look and behaviour itself, which it mostly does well. Screen readers still work: Flutter passes a description of each screen to VoiceOver and TalkBack.

Performance in real business apps

In a business app, users notice three things: how fast it opens, whether scrolling is smooth, and how long they wait for data. A well-built Flutter app opens quickly and scrolls smoothly on mid-range phones. The wait for data depends on your server and the network, not on the framework.

When a Flutter app does stutter, the cause is usually the app's own code: very large images decoded at full size, a whole screen rebuilding on every small change, or heavy work such as parsing a big response on the main thread. Native apps stutter for the same reasons.

The fix for the last one is to move the work to a background isolate, which in Dart takes a few lines.

Always judge speed in a release or profile build on a real mid-range phone. Debug builds are slower by design, so never judge an app by one.

import 'dart:convert';
import 'dart:isolate';

Future<List<Order>> parseOrders(String body) {
  // Decoding a large response on the main isolate blocks the UI.
  // Isolate.run moves the work to a background isolate.
  return Isolate.run(() {
    final items = jsonDecode(body) as List<dynamic>;
    return [
      for (final item in items) Order.fromJson(item as Map<String, dynamic>),
    ];
  });
}

What one codebase really saves

With Flutter there is one set of screens, one set of business rules and one test suite. A feature reaches both stores on the same day, and a bug is fixed once instead of twice.

It also saves coordination. With two native apps, every change is designed, built, tested and released twice, and the two apps slowly drift apart: a button in one place on iPhone and somewhere else on Android, or a feature that only one of them got.

What it does not do is cut the whole project in half. Design, the backend, content, testing on real devices and store work take the same time either way. Flutter shrinks the part where screens and logic are written. That is often the largest part, but it is not the only one.

What you still do once per platform

Some work stays specific to each platform, whichever way you build:

  • Two developer accounts: the Apple Developer Program and the Google Play Console
  • Signing: certificates and provisioning profiles for iOS, an upload key and Play App Signing for Android
  • Permissions: usage descriptions in Info.plist for iOS, permission entries in AndroidManifest.xml for Android
  • Push notifications: Apple's push service needs its own key and setup, even if you use Firebase Cloud Messaging for both
  • Privacy forms: App Privacy details in App Store Connect and the Data safety form in Google Play
  • A store listing, screenshots and a review for each store
  • A Mac with Xcode, or a cloud build service with Mac machines, to build the iOS version
  • Testing on real iPhones and Android phones of different sizes

Platform features and plugins

Flutter reaches device features through packages published on pub.dev. The everyday ones are well covered: camera and photo picking, maps, location, push notifications, in-app purchases, fingerprint and face login, deep links, local storage and web views. Many of them are maintained by the Flutter team or by Firebase.

Before you commit, list the features your app cannot launch without and find a package for each one. For every package, check who publishes it (the verified publisher badge helps), when it was last updated, which platforms it supports, and how open issues are handled.

If your payment gateway, map provider or hardware vendor only offers a native SDK, that does not rule Flutter out. It is extra work, though, and it should be planned and priced from the start.

Calling native code from a Flutter app

When no package exists, for example for a local payment SDK or a vendor's scanner library, that part is written natively and called from Dart through a platform channel. The Kotlin and Swift code registers a handler under the same channel name, and Dart calls it like any async function.

For larger integrations, Pigeon, a package from the Flutter team, generates type-safe code for both sides, so you are not passing loose maps around. Either way, the native part is usually small and the rest of the app stays in Flutter.

This is also Flutter's honest limit: someone on the project needs to be comfortable in Xcode and Android Studio. A Flutter developer who never touches native code will get stuck on the first unusual SDK.

import 'package:flutter/services.dart';

class NativeScanner {
  // The Swift and Kotlin code registers a handler under this same name.
  static const _channel = MethodChannel('com.example.app/scanner');

  /// Opens the vendor's native scanner and returns the scanned code.
  Future<String?> scan() async {
    try {
      return await _channel.invokeMethod<String>('scan');
    } on PlatformException {
      return null; // The native side reported an error.
    } on MissingPluginException {
      return null; // No native handler on this platform.
    }
  }
}

App size

A Flutter app carries its engine and framework, so an empty Flutter app is a few megabytes larger than an empty native one. In a real app the heavier items are usually images, fonts, animations and third-party SDKs, and those weigh the same whichever way you build.

Both stores already send each phone only what it needs: Google Play builds per-device APKs from your app bundle, and the App Store thins the download for each device. Flutter can also show you exactly what takes the space, and keep debug symbols out of the app.

# See what takes space in an Android release build
flutter build appbundle --analyze-size --target-platform android-arm64

# Release build with Dart symbols stored outside the app
# (keep build/symbols to read crash reports later)
flutter build appbundle --obfuscate --split-debug-info=build/symbols

Making it feel right on iPhone and Android

Because Flutter draws its own widgets, how platform-specific the app feels is your decision. Some things adapt by default: page transitions, the swipe back on iPhone, scrolling that bounces on iOS and stretches on Android, and text selection handles.

Other things need a decision: switches, dialogs, date pickers and loading spinners. Flutter has adaptive versions such as Switch.adaptive and showAdaptiveDialog that use the iOS style on Apple devices. Many brands go the other way and use one custom design on both platforms, which works fine as long as navigation and gestures behave the way each platform's users expect.

What I avoid is an app that looks like Android on an iPhone: Material ripples everywhere, a floating action button in the corner, Android-style date pickers and dialogs. Users may not be able to name the problem, but they feel it.

Arabic and right-to-left support

This is one of Flutter's strengths for apps aimed at Egypt and the Gulf. Turn on the Arabic locale and the whole layout flips right to left, as long as padding and alignment are written with start and end instead of left and right. Dates, numbers and plurals come from the intl package, and translations live in ARB files that Flutter turns into Dart code.

Native platforms handle Arabic well too: SwiftUI uses leading and trailing, and Compose uses start and end. The difference is that with native you do the right-to-left work, the translations and the testing twice, in two codebases, and keep them in step.

Whichever way you go, test with real Arabic text rather than English placeholders, and check mixed content such as phone numbers, prices and English brand names inside Arabic sentences. My separate guide on Arabic and RTL in Flutter covers the details.

Hiring, maintenance and long-term risk

With Flutter you hire for one skill set. With native you need Swift and Kotlin, which usually means two developers, or one rare person who is strong in both. For a small company, that difference matters more than any benchmark.

Maintenance is never zero. Apple and Google release new OS versions every year, Google Play keeps raising the target API level that apps must meet, and Apple raises the minimum Xcode version for uploads. A Flutter app also needs Flutter and its packages updated a few times a year. Plan regular upkeep even in a year with no new features.

On long-term risk: Flutter is open source, developed by Google with a large outside community, and the code you own is plain Dart. The realistic risk is not Flutter disappearing; it is an important third-party package being abandoned. Keep dependencies few, prefer official ones, and wrap each one behind a small class of your own so it can be swapped.

Native has its own version of this. SwiftUI and Compose change quickly, and older UIKit or Android View code takes work to keep current.

Web and desktop as a bonus

Flutter can also build for the web, Windows, macOS and Linux from the same code. That is useful for an admin panel, a dashboard for staff, or an internal tool that mirrors the app.

It is not a good fit for your public website. Flutter on the web draws into a canvas, loads more code on the first visit and is weak for search engines. A company site, a blog or an online store should be a normal website built to show up in Google. Treat Flutter web and desktop as a bonus, not as the reason to choose Flutter.

Where React Native fits

React Native is the other main cross-platform option. You write JavaScript or TypeScript with React, and it renders each platform's own native components. The React Native team recommends starting new projects with a framework such as Expo, which handles builds and many native modules for you.

It makes sense when your team already works in React on the web and wants to share people, patterns and some code with the app. Flutter makes sense when you want one consistent UI that you fully control and a single toolkit for everything on the screen. Both are mature, and the deciding factor is usually the team you have, not the framework.

I build in Flutter, so weigh my view with that in mind. If you have a strong React team, React Native is a perfectly reasonable choice.

When native is clearly the better choice

I recommend native, or at least a native part, in these cases:

  • Augmented reality or real-time 3D is the core of the product, built on ARKit, RealityKit or ARCore
  • It is a game: an engine such as Unity or Godot usually fits better, though Flutter's Flame engine suits simple 2D games
  • Deep OS integration is the product: CarPlay or Android Auto, keyboard or VPN extensions, heavy background processing, or tight work with Bluetooth hardware
  • Home screen widgets, Live Activities or an Apple Watch app are the main experience, not an extra. These are written natively even inside a Flutter app
  • You need a new OS feature on the day Apple or Google releases it
  • The product is single-platform, such as an iPad-only app or an Android app for company devices, so a shared codebase saves nothing
  • You already have a working native app and a native team. Rewriting it rarely pays off

Common mistakes when choosing

These are the mistakes I try to help clients avoid:

  • Choosing from benchmark videos. Choose from your feature list and your team.
  • Expecting Flutter to halve the whole budget. It saves on screens and logic, not on design, backend, testing or store work.
  • Assuming native is automatically faster. A badly built native app stutters too; build quality matters more than the framework.
  • Leaving the riskiest feature for later. If the app depends on one SDK or device feature, build a small proof of it in the first week.
  • Forgetting the backend. The API, the admin panel and the notifications are often as much work as the app itself.
  • Hiring a Flutter developer who never opens Xcode or Android Studio, so releases, signing and native SDKs stall.
  • Rewriting a working app because a new framework is popular.

A decision checklist and what to do next

  • Do you need both iOS and Android at launch, or can one wait?
  • Is any must-have feature AR, 3D, a watch app, a widget or a deep system integration?
  • Does every SDK you depend on, such as your payment gateway, maps or chat, support Flutter, or can it be wrapped with a platform channel?
  • Will the app be in Arabic, English or both?
  • Who will maintain it, and which skills does that person or team have?
  • Is there an existing app or codebase you want to keep?
  • Do you also need a web dashboard or admin panel?

If you need both platforms, the features are business features, and the answers to the AR and SDK questions are no or manageable, Flutter is the sensible default. If one platform is enough, or the product lives where only native does well, go native.

As a next step, write one page: who the users are, the must-have features, the platforms, the languages and the systems the app connects to. Mark the one or two features you are least sure about. Send that page to me or to any developer you are considering, and ask two things: which approach they recommend and why, and what they would prototype first to remove the risk. A good answer names trade-offs; a weak one only names the tool they always use.

If you want my view on your project, get in touch through this site. I will tell you which way I would build it and what drives the cost in your case.

Common questions

Is Flutter as fast as native?
For business apps such as shopping, booking, delivery or content, users will not see a difference in a well-built release build. Flutter compiles to machine code and draws with its own engine. Native keeps the edge in heavy 3D, augmented reality and work that sits very close to the operating system.
Is Flutter cheaper than native app development?
Usually, when you need both iOS and Android, because the screens and logic are written once and one team maintains them. It does not reduce design, backend, testing or store work. The real cost depends on features, integrations and design, so ask for a quote based on a written feature list.
Does a Flutter app look like an iPhone app on iOS?
It can. Navigation, scrolling and text selection follow iOS by default, and adaptive widgets switch to the iOS style. Many brands choose one custom design for both platforms instead, which also works when gestures behave the way each platform's users expect.
Can a Flutter app use native iOS and Android features?
Yes. Most device features have Flutter packages, and anything else can be written in Swift or Kotlin and called through a platform channel. Home screen widgets and watch apps are written natively and share data with the Flutter app.
Should I choose Flutter or React Native?
Both are mature cross-platform options. Pick React Native if your team already builds with React and TypeScript, and Flutter if you want one UI toolkit you fully control and the same look on every device. The team you have matters more than the framework.
Will Google drop Flutter?
Nobody can promise what any company will do in the future. Flutter is open source, Google develops it actively and uses it in some of its own apps, and a large community contributes to it. Your code is plain Dart that you own, and the bigger everyday risk is an abandoned third-party package, which you manage by keeping dependencies few.
Can I move an existing native app to Flutter gradually?
Yes. Flutter's add-to-app support lets you add Flutter screens to an existing iOS or Android app one feature at a time. It only makes sense with a clear reason, such as merging two native apps that have drifted apart. A working native app with a happy team is usually best left alone.

Share

Available for new projects

Profiles