Flutter vs Electron: Lewis Cianci’s opinion article on why you might choose Flutter over Electron for your next desktop app.
Today, many apps that we use on our desktops are created in Electron. It seems like fewer and fewer companies are choosing to create their apps in a native language for the platform and are instead opting for a cross-platform solution. In fact, Electron seems to have become the de facto choice for companies creating desktop applications. On paper, the value proposition is quite good, as you may be able to reuse your knowledge of HTML and JS to create desktop apps.
More recently, Flutter has reached beta for use on desktop operating systems, like Windows, Linux and macOS. Personally, I believe that this technology has the potential to embrace quite a significant portion of the desktop application market.
But why would you even think about using Flutter when Electron is used to make so many high-quality apps today? To understand this, let’s first talk about why Electron is so popular these days.
Electron lets you use web technologies in your desktop app
Electron’s tagline on their website is “If you can build a website, you can build a desktop app.” This is immediately appealing to people who are already quite good at creating websites and would like to reuse their knowledge to create a desktop app. On paper, this sounds amazing, but I would like to put it to you that web technologies are poorly suited to creating desktop applications. That feels like an out-of-place opinion to have in today’s web-first world, but it’s something that I’ve found to be true time and time again. Let’s run through why.
It can get complicated pretty quickly
Normally, it’s very easy to create an Electron app with some basic HTML, JavaScript and CSS. Many people’s first apps that start out like this are trivially simple affairs, and they can easily create a basic app that runs on Windows, Linux or Mac. And all is good with the world.
The moment you want to accomplish something a little more complex, you’re probably going to begin to leverage a third-party JavaScript framework, like Angular, React or Vue. These frameworks will have dependencies as well. So, next up, you need to configure webpack to bundle all your dependencies and put them together for use by Electron.
Webpack is a well-made, very complex tool. Additionally, what webpack is tasked with is incredibly complex in itself. It wires up all your code alongside the dependencies for your app into bundles of JavaScript that can be consumed by the browser (or, in this case, Electron). The critical importance of this going well cannot be overstated. If you get it wrong, your app just won’t work, or worse, certain parts of your app won’t work right. If you introduce new dependencies that are a bit older or haven’t been maintained in a while, this will make webpack strain ever harder as it tries to wrap all your stuff up into a single cohesive script.
There’s no universally accepted way to bundle your app using tools like webpack, and you can wind up with a configuration that’s completely wrong. In these times, it can be hard to work out exactly where the problem is or how to move forward, and it can get pretty frustrating pretty quickly.
And why are we doing this in the first place? Because we’re trying to use a tool for our desktop app that was originally designed for websites. Webpack wasn’t created for desktops – it was created for the web. The configuration to set this up is a little unwieldy, to say the least. A lot of the functionality that webpack offers (like splitting bundles) is only a good idea to use on the web. For your desktop app, it’s a different story.
Disk usage
Right now, you have more than one Electron app on your computer. Because Electron is essentially a “browser in a box,” every Electron app also comes with the Electron framework, which weighs in at an astonishing 120 MB. Because of how Electron works, you can’t install the framework on your computer and then get all the other apps that use Electron to use it. Every app comes with its own framework. That means if you had ten apps that you had made in Electron stored on your system, even if the apps themselves were only “Hello World” apps, they would take up over a gig.
It’s so big because the redistributable houses most of the Chromium framework, so it can read and parse HTML and interpret JavaScript. These dependencies add to the bulk of the installed app on the computer.
Usability and responsiveness
Making apps in Electron means that you are using HTML to define how your app looks and then using JavaScript to define the business logic. Because JavaScript is compiled Just In Time (JIT) and not Ahead Of Time (AOT), your app will simply run a little bit slower. “A little bit” is highly subjective, but as the complexity of your app grows and it incorporates more exciting functionality, the performance of your app can start to slow a little bit.
Of course, it’s very cool these days to beat the dead “JavaScript is slow” horse. But the fact remains that even with the significant improvements we’ve seen over time in JavaScript engines, it still isn’t as performant as frameworks that offer AOT compilation. More recently, we’ve seen the rise of technologies like WebAssembly, which offer greater performance than JavaScript. WebAssembly is great for apps that run on websites that you interact with through your browser. But even if your app executes quicker due to the use of WebAssembly, you are still saddled with the use of HTML to visually describe your application.
The case for Flutter
Flutter has only been available for phones for a relatively short time, and now it’s starting to offer preliminary support for desktop environments as well. It’s perhaps not the best time to release an app for general use (because desktop support isn’t finalized yet), but it’s definitely the right time to start to learn about Flutter for desktop.
Why would we, though? There are already quite a few cross-platform solutions available to us as developers, like Electron. Why should we learn yet another framework when solutions exist that already let us accomplish this task? And more than that, why would we start learning about a framework whose desktop offering isn’t even stable just yet? There are a few good reasons:
Reason 1: Flutter Performance
Electron apps use HTML to design the UI and JavaScript for the business logic. I’m just going to say it – HTML is a poor fit for desktop apps. It wasn’t ever designed to describe the UI of a desktop application, and while it is possible to do so, it’s not expressive or intuitive to do this. Plus, unless your app is just a static set of pages, you can’t actually get your HTML to do anything without using JavaScript to adjust the DOM.
Companies have certainly succeeded in creating applications using Electron and then shipping those applications, but these applications have never felt “native” or had native performance. They’ve come extremely close at times, but Electron apps have always had inconsistent performance and increased memory usage when compared to their native counterparts.
In the “extremely close” category, we have apps like the Slack client on desktop and the Discord client. These are both Electron apps and work reasonably well. The performance of these apps is probably due to the exceptionally clever people at these companies developing performant clients of these applications for the web, and these benefits have simply flowed through to the desktop applications.
However, some Electron apps are terrible from a performance standpoint and frequently jank while in use or become unresponsive. A great example of an app like this is Microsoft Teams. I use Teams daily for my work and find that completing even basic tasks, like switching between tabs, takes far too long, and performance issues are very prevalent throughout the app. I’m not the only person with this problem. The predecessor to Teams on desktop was Lync, and while Lync certainly had its issues, it was a native experience on the computer that was written natively for Windows. The performance difference between these two implementations could not be more stark. Switching to another tab in Lync was almost instant, whereas changing a tab in Teams can take 5–10 seconds of jank. These kinds of pauses really break the user’s experience and can make people question the quality of your app. It also makes the user feel like the app itself is of low quality.
On phones, Flutter compiles to machine code, so performance is very good. And on desktop, it’s the exact same thing. No time is spent attempting to interpret your code on the fly, as it is compiled ahead of time, ensuring that your app is performant. Even when there are complicated draw calls, Flutter can push a surprising amount of UI out and maintain a solid 60 frames per second.
Because Flutter isn’t running an instance of Chromium to try to render your app but is instead running on the machine as a native app, performance is vastly improved. Memory usage is reduced, and apps feel snappier and more responsive.
Reason 2: Type-safe UI definitions
If you write your app in Electron and in HTML, and your code is either completely wrong or just a little bit wonky, Electron will still do its best to parse and display what you have written. The HTML standard has been around for a long time, and there are a variety of clever hacks that modern-day browsers use to ensure that webpages are displayed properly. If you are using a more recent framework, like Angular, with Electron, you might have some type-safety goodness that makes your app fail at compile time (because your HTML isn’t valid), but still, it’s pretty minimal. This can make it difficult to work out why your app doesn’t display in a certain way or why it has a strange visual presentation.
With Flutter, as you are designing the UI for your app in the same language you write the business logic in, it won’t actually let you write incorrect UI code. Your UI winds up having the same level of type safety as the business logic for your app, which is pretty impressive. These safeguards ultimately save you time, as time spent debugging the problem with your app is reduced.
Reason 3: Flutter has a better use of space
As we mentioned above, “Hello World” in Electron uses up about 100 MB and is duplicated for every Electron app a user has on their computer. The reason for its large size is that every Electron app has most of the Chromium browser and Node. On macOS, an app I just built now weighed in at about 50 MB. Straight away, this is a reduction of 50% compared to the size of the Electron app. Flutter is able to achieve much better space efficiency due to how apps are built and linked together.
For an Electron app, users receive a light instance of Chromium as well as dependencies for the app itself. But due to some of the idiosyncrasies of JavaScript, it’s not easy to tree-shake your Electron app (or just retain the bits of the app that are used). JavaScript also has reflection as a language feature, which further hampers your ability to effectively tree-shake your app. You can optimize your bundling and minification process to strip out more of your app and reduce the size further, but this comes with an increased risk of accidentally stripping out parts of your app that are in use (and this will cause runtime errors).
Dart (the language that Flutter is written in) doesn’t have reflection. It might sound weird to preach about the lack of a language feature being a good thing, but not having reflection means that your app knows at compile time exactly what part of the app is being used, as it won’t be dynamically invoked or created at any time. This leads to far better tree-shaking and less use of your disk. These days, storage is pretty cheap, so this isn’t a huge issue. But it still feels weird when the app that changes my keyboard lights from blue to red somehow has a 150-MB installer.
A better path to mobile
While you can write an app in Electron, there’s no clear way to then move your app to mobile phones like Android or iOS if you choose to. It’s true that with a little bit of effort, you could probably bootstrap your app through something like Cordova and ship it to mobile phones. But it’s not really a supported path for Electron apps – you have to wire something up yourself. And then you have all the performance and usability issues of running your app through Cordova on a phone.
With Flutter, you can build your app for iOS, Android, Windows, Mac and Linux (not to mention the Web). All of the apps you produce can come out of the same IDE and be the result of the same build process. This makes for a simpler building and packaging process.
Flutter desktop vs Electron: A time to learn
As mentioned at the outset of this article, Flutter desktop support hasn’t landed in stable just yet. Due to the similarities between macOS and iOS, it’s the best experience on the macOS desktop at the moment, but Windows and Linux aren’t that far behind. Plus, Canonical has partnered with Google to develop future desktop apps for Ubuntu in Flutter. And, obviously, due to the age of Electron and the comparative newness of Flutter for desktop, some of the native functionality present in Electron (like notifications, taskbar icons, etc.) is not yet available for Flutter. But this gap won’t hang around for long.
That means that while we probably wouldn’t release a production app for Flutter just yet, it would be a great time to start using Flutter to develop some basic desktop apps. In the not-too-distant future, when Flutter desktop support starts to mature, you can be in a better position as a developer to start using it. The apps you build have a good chance of being more aesthetically pleasing, more performant, and taking up less storage on your customers' computers. So, if you’ve been on the fence about this (or have even been completely unaware of desktop support for Flutter), it’s definitely a great time to start down this path.
Learn how to get started with building Flutter desktop apps.
Further reading:
- Releasing your Flutter desktop application by Rody Davis Jr
- Invoice Ninja: We threw away six months of work to start over using our mobile app (Flutter) as the base for the new web/desktop app
- Flutter macOS desktop publishing with Codemagic by Chris Raastad (Product Manager at Codemagic)