Flutter for Web

Flutter for Web

At Google I/O 2021 Flutter 2.2 was announced with improvements on the development experience and performance of the built apps.

Let's see how Flutter can help you as a web developer - and take a close look under the hood of the Flutter web stack focusing on performance.

To install Flutter on your operating system check out the official Flutter docs here. They cover every major operating system (Windows, mac OS, Linux and even Chrome OS).


To check which version of Flutter you are currently running just type:

flutter --version

This should print out:

As we are focusing on the support for Web apps in this post, you should check which devices are targeted by your flutter installation:

flutter devices

This should print out:

You should see at least one (web) entry - Chrome on my machine. And as I am working on my MacBook there you can see the macOS device target as well. But let's focus on the web version for now.

We will compare the performance of the develop - and production builds by comparing what chunks of data are loaded in the browser.


Create the scaffold with:

flutter create webapp

This reminds me on popular CLI tools such as Angular's ng tool:

ng new webbapp

or React's create-react-app.

Pretty simple and you get a full working web app with just a few commands in the terminal.

Ok, back to Flutter: After successfully creating our Flutter webapp the freshly created folder looks like this:

Looks good.

Let's start the web app with:

flutter run -d chrome

Remember the list of devices from flutter devices?
The -d flag ensures that we run the app with Chrome as web app. The flag is optional, if you skip it and have more devices in your flutter environment the CLI asks you which to choose. Go for the web option to follow our analysis along.

After successfully launching the app a new Chrome instance is started on your machine and should connect to your running web app:

If everything works fine you should see something like this in a new Chrome instance:

Pretty cool!
The scaffold sets up a fully themed Material Web app containing a Stateful widget. By pressing the +-Button you can increment the counter which is displayed in the center.

Analysis of Flutter web

Ok let's take a closer look on how Flutter generates web apps.

At first we run a Lighthouse audit on the development version of the generated web app:

Pretty ok for a development build as this is still unoptimized code.

  • 100 points for Best practices
  • 92 points for SEO
  • 78 points for Accessibility
  • ? for Performance - Huh? Let's check the details:


To get a more detailed view on the overall performance of the generated web app we switch to the Network tab of the Chrome Dev tools:

By sorting all requests by size we see the biggest chunks of data loaded for the Flutter web app:

  • 1.0 MB: client.js
  • 292 B: main_module.bootstrap.js
  • 202 B: dart_sdk.js

Let's recap these numbers:

With 1.0 MB client.js is by far the biggest chunk that might block our app on slower network connections in production. Let's see if we can get rid of this in production mode.

292 B for main_module.bootstrap.js is quite impressive and can be considered as a small memory footprint.

But what's really impressive is
202 B for the dart_sdk.js

That's pretty neat! Very small network usage for the dart_sdk.js. Cudos! Nice work, Google!

Ok - time to switch to production mode.

Production build of the Flutter web app

To start a production build of the Flutter web app, just enter:

flutter build web

This might take some time (27,7 s on my machine) and should print out this on your console:

When we fire up the Chrome Dev tools and switch to the Network tab as in the development version we see a similar Network Log table:

Interesting! Let's see what comes down the wire for the Flutter web app scaffold:

  • 1.4 MB: main.dart.js
  • 1.3 MB: MaterialIcons-Regular.otf
  • 284 kB: CupertinoIcons.ttf

So the biggest chunk for the production build is - by far - main.dart.js.

Let's switch to the Source Tab in Chrome Dev Tools to take a closer look on what this file actually is:

It's our minified app with the client.js (already seen in debug mode previously).

Ok that's cool, but it's still quite heavy.

But here is something strange coming down the wire as well:


Why does Flutter send this to the browser? We didn't even integrate it?

It turns out that the Cupertino Icons are activated by default in pubspec.yaml in the scaffold and are not optimized away in the production build:

Just be aware of that and remove it from the pubspec.yaml.


Flutter does an amazing job for providing the basis of building ambient apps for Android, iOS, mac OS, Linux, Windows and the Web.

To get the most out of the framework you still need to optimize a bit - but we expect Google to improve on this in future releases.