- It’s an open-source software development kit (SDK), developed by Google, to quickly build iOS and Android apps, sharing most of the code. It works in conjunction with the Android and iOS SDKs, which also means you still need a macOS machine to build for iOS (just like you do for React Native and Xamarin). The installation for Android was very smooth for me — I just followed the instructions on the website and used the ‘flutter doctor’ command, but I initially had some issues with the iOS setup. This article by Laxman Sahni helped set it up correctly.
- It uses the Dart programming language, also developed by Google. Yes, another language to learn but don’t worry, it’s super easy if you’re familiar with Java, JS, Kotlin, Swift or C#.
- The application is compiled ahead-of-time into native ARM code, not at runtime as in React Native. This gives better performance because there’s no JS bridge in the middle to parse and execute the code. However it also means there’s no over-the-air update option by downloading a new bundle of JS code at runtime.
- Rather than being a wrapper on top of the iOS/Android-specific native UI components (which is what React Native and Xamarin do), it really draws the UI from scratch on a ‘screen canvas’, through a fast C++ 2D graphics library called Skia (which also serves as the graphics engine for Google Chrome, Chrome OS, Android, Mozilla Firefox and Firefox OS, and many other products). The Skia project started back in 1996 and was acquired by Google in 2005, although it’s released under the BSD license and anyone can use it. This has huge consequences — I talk more about this in the pros and cons sections below.
- Similarly to React Native, Flutter is also based on a ‘unidirectional data flow’ architecture, or reactive programming, briefly but clearly explained here by Elizabeth Denhup. In even fewer words, the app reacts to user input by changing variables/properties (or more generically, the ‘state’ of the screen or view), and the UI is re-rendered according to the new state. Functions don’t change the UI (the colour of button, the text of a label, the content of a list, etc.), directly.
- Again, similarly to React Native, there is hot reloading (thank God!). You just change something in the code editor, save, and the UI refreshes on the Android emu or iOS sim. It’s so convenient and fast that it’s hard to go back once you try it and it makes up for the fact that the UI is created programmatically and therefore there’s no visual editor for it.
- Flutter is extensible with third-party plugins that add new custom-drawn UI components or wrap platform-specific features not already covered by the built-in classes (eg: for video/audio, monetisation, storage, camera, augmented reality, machine learning etc.). Here’s the best collection of plugins I’ve found. There are many, but not as many as you might need.
- Linked to the previous point, Flutter makes it relatively easy to write platform-specific code by either executing different code after checking Platform.isIOS and Platform.isAndroid (if there’s a difference in the UI widgets you want to instantiate, or logic in your .dart file), or by writing your own native plugins (if you really need to wrap platform-specific functionalities not provided by Flutter already).
- Also linked to point 7, performance should not be a problem for typical apps (at least in release mode — debug mode is significantly slower because it uses a virtual machine to run Dart code), as the UI is written by a fast low-level C++ lib, and other functionalities map to their native counterparts. However, you must do it right, by minimising the number of redraws and by redrawing only parts that actually depend on the changed state. Refer to this article by Andrea Bizzotto and this other one by Simon Lightfoot to find out more.
- You can use any text editor and the flutter command to write and build apps, but the recommended approach is to use one of the editors that support the Flutter plugin, namely Android Studio (my choice), VS Code or Intelli J. This gives you intellisense, autocompletion, some debugging tools and spares that you need to use the command-line to compile/run the apps.

To get a sense of the performance and the look and feel of a Flutter app in comparison to a Native app, just download the Flutter Gallery app from the Play Store (and maybe look at its source code on GitHub). Also, refer to the Widget Catalog page in the official docs.
The advantages of using Flutter:-
- The fact that Flutter does its own UI drawing rather than being a wrapper around the platform-specific native components has both pros and cons. The pro is that if something is rendered in some way on your test iPhone with iOS 12, for example, it should be rendered in exactly the same way, not only on any other iOS version but also on any Android phone. With React Native or Xamarin, the UI components have a number of properties that are only supported in one platform or the other, or maybe they are supported but translated in slightly different ways to their native counterparts behind the scenes. This means that you either need to test on a lot of devices and OS versions (and potentially write platform specific code to fix some situations), or just know that it might look broken (or at least different) for some users. Your app might even crash if you use an attribute or a feature that’s not supported on a specific OS version. With Flutter you will be much safer (at least for the UI part of the app). You should still check the app on multiple devices, especially if you use third party plugins that do map to underlying platform-specific native components. This will be the case if you use things like audio/video, push notifications, in-app billing etc.). The negative side of this approach is covered in the next section of the article.
- Hot reloading is just too useful, it’s a developer’s dream come true: ⌘+S in the editor, and the app reloads in a sec on the sim! Goodbye to the endless build / wait / run / wait / test / start-over endless process. In reality you still need to rebuild when you change assets and plugins, change something in the navigation, state initialisation or logic, but most UI changes are applied immediately while the app is running. For apps that are UI-heavy, this is where you’d dedicate most of your time.
- I like the overall principle of small reusable components that react to a change in the ‘state’, which is also one of React’s and React Native’s core ideas. Reactive apps can also be developed in pure iOS and Android development of course, but it’s easier and more natural with Flutter (and RN). This is because it’s at the core of the technology, rather than something that’s provided by third-party libs and implemented in dozens of different ways.
- Dart is simple but a powerful and complete language, comparable to Swift, Kotlin or Java. Asynchronous programming with async/await/Future is a breeze, and it also feels complete and consistent (I can’t say the same about JavaScript).
- Flutter and Dart have built-in support for both unit testing for logic, and widget testing for UI/interactions. For example, you can send tap and scroll gestures, find child widgets in the widget tree, read text, and verify that the values of widget properties are correct. The official docs does a good job at clearly presenting what’s available. This article by Devon Carew shows how the Flutter plugin makes it all well integrated into your code editor.
- I love the built-in support for theming every aspect of the app’s UI. The most difficult part in creating the light and dark themes of my app was actually picking the right colour (I created just two, but could have created 10 with the same approach). In terms of code, it’s just a few lines (basically set the theme property of the root MaterialApp object — see this for a full example).
The Disadvantages of Flutter:-
I have to say I didn’t really find anything that deserved to stay under a “bad” or “ugly” section, but here’s a list of things that aren’t as good, at least from certain point of views:
- As mentioned a couple of times already, Flutter paints the UI on its own custom way, it doesn’t create native components. It does a very good job at replicating Android’s Material Design and also iOS-specific components with its Cupertino library but it’s still not native under the hood. This has a few implications, such as:
(A) If iOS 13 changed the way a segmented control or a UISwitch is rendered, your Flutter app that uses CupertinoSegmentedControl or CupertinoSwitch would keep the old look until Flutter is updated and you rebuild it. One can argue that many users wouldn’t care (most of my non-techy friends wouldn’t care and wouldn’t even notice, for example, they’d just care about the app looking pretty enough rather than whether it’s 100 per cent consistent with the OS’s pure look and feel), but it might be a deal breaker if you’re a purist.
(B) If you plan to use Flutter for just a section of an existing app (which is covered here in Flutter’s wiki, here in an article by Tomek Polański, and here in an article by Jan Reehuis), you might see a difference between the native part and Flutter part. Again, this might bother you (and your users) or not. Much less of a problem for new apps that are 100 per cent Flutter of course.
(C) To make things as easy as possible for you as a dev, and assuming that your users don’t care about the native look of the app, you could just use MaterialApp (which uses Material Design components) and compile it for both Android and iOS. It will work fine, despite the non-native appearance, and it is in fact what I did for my app. If, instead, you do care about this, and decide to use MaterialApp for Android and a CupertinoAppfor iOS, you’ll be duplicating most if not all the code for your UI (which can be a considerable part of your app), and you’ll make the architecture more complex. Consider this carefully and decide if it’d be worthwhile. - Here is a decent list of great looking UI components and other pluginson GitHub, but it’s nowhere as rich as the plugins you can find for React Native and even Xamarin. It’s probably just because Flutter is much newer and with a smaller community but that’s how things are at the moment. Choices are limited, and many plugins are old, not maintained, and maybe don’t even work anymore with the current Dart/Flutter versions. Some components (especially non-UI ones, that map platform-specific features) are only available for either iOS or Android, but not both (typically they support Android, because Android devs are more into Flutter than iOS devs at the moment, since Flutter comes from Google). It’s true however that filling in the gaps and writing the platform-specific code just for the missing platform is still better than starting from scratch and things will improve for sure if Flutter keeps getting more and more popularity.
- Debugging is not at its best. You can use the print/debugPrintstatements, look at logs, and use tools to profile the CPU/memory or visualise the view hierarchy, but we’re on a different planet in comparison to what you do in Xcode or Android Studio working with the native SDKs. (More about your options in the official docs here.)
Correction: a number of people have reported that this point is not correct, and that you can use breakpoints, step through the code and inspect variable values just like with Java/Kotlin Android. This applies to both Android Studio and VSCode. Great news then 😉 - The error screen or logs that you get when there’s a layout error (or something else at a lower level) can be very confusing and obscure, as it points to some line of code of the framework that is maybe many levels of abstractions below what you directly interact with. On native iOS and Android, errors are usually clearer to understand, and, if not, you can typically just copy and paste the full error on Google and be reasonably confident that you’ll get a useful list of links that tell you more. With Flutter, since the community is still relatively small, not so much.
- Creating the UI programmatically (in the same .dart files where your code for the screen is) is easy and direct. It also means there’s not much separation. I would prefer to create the UI with markup code (similar to what you do in native Android apps) in separate files.
- On Android, the vast majority of developers use Clean Architecture and MVP (model-view-presenter). On iOS, it can be MVC, MVVM (model-view-viewmodel) or Viper. In both cases (but even more for Android) there are clear and well known architectural patterns that have proven to work well for large apps. For Flutter (and React Native as well), it feels like it’s all still being defined, there is no ‘standard’ or ‘almost-universally-accepted’ architectural approach. All articles show simple samples, which is normal because they still need to take people onboard before talking about more advanced aspects. However, if you plan to use Flutter for a rather large project, it would be preferable to have a clear idea of how to structure it, so that it’s scalable and easily maintainable as the app grows in size and complexity. I highly recommend watching this video from Brian Egan to start looking deeper into this (it covers layering your code, Redux and testing) and checking out his samples on GitHub. I also recommended this article about Streams and RxDart by Didier Boelensand these other posts about Redux and overall architectural review. Again, I’m definitely not saying Flutter doesn’t allow you to build apps with a clean and maintainable architecture, but just that there’ll be some trial /error / experimentation / study involved, as it’s not something as mature and widely used as what we’re accustomed to in native iOS/Android apps.