Skip to main content

Flutter web app initialization

Customize how Flutter apps are initialized on the web.

This page details the initialization process for Flutter web apps and how it can be customized.

Bootstrap the app

#

The flutter build web command produces a script called flutter_bootstrap.js in the build output directory (build/web). This file contains the JavaScript code needed to initialize and run your Flutter app. You can use this script by placing an async-script tag for it in your index.html file in the web subdirectory of your Flutter app:

html
<html>
  <body>
    <script src="flutter_bootstrap.js" async></script>
  </body>
</html>

Alternatively, you can inline the entire contents of the flutter_bootstrap.js file by inserting the template token {{flutter_bootstrap_js}} in your index.html file:

html
<html>
  <body>
    <script>
      {{flutter_bootstrap_js}}
    </script>
  </body>
</html>

The {{flutter_bootstrap_js}} token is replaced with the contents of the flutter_bootstrap.js file when the index.html file is copied to the output directory (build/web) during the build step. Inlining the bootstrap script eliminates an extra network round-trip during startup. For production optimization guidance, refer to Reduce cold-start latency.

Customize initialization

#

By default, flutter build web generates a flutter_bootstrap.js file that does a simple initialization of your Flutter app. However, in some scenarios, you might have a reason to customize this initialization process, such as:

  • Setting a custom Flutter configuration for your app.
  • Integrating a custom service worker for offline support or caching.
  • Writing custom JavaScript code to run at different stages of the startup process.

To write your own custom bootstrapping logic instead of using the default script produced by the build step, you can place a flutter_bootstrap.js file in the web subdirectory of your project, which is copied over and used instead of the default script produced by the build. This file is also templated, and you can insert several special tokens that the build step substitutes at build time when copying the flutter_bootstrap.js file to the output directory. The following table lists the tokens that the build step will substitute in either the flutter_bootstrap.js or index.html files:

TokenReplaced with
{{flutter_js}} The JavaScript code that makes the FlutterLoader object available in the _flutter.loader global variable (refer to Customize the Flutter loader ).
{{flutter_build_config}} A JavaScript statement that sets metadata produced by the build process which gives the FlutterLoader information needed to properly bootstrap your application.
{{flutter_service_worker_version}} Deprecated. Previously substituted a build version number for Flutter's legacy service worker loader. Flutter no longer generates or registers a caching service worker; refer to Service worker deprecation and the Web FAQ .
{{flutter_bootstrap_js}} As mentioned above, this inlines the contents of the flutter_bootstrap.js file directly into the index.html file. Note that this token can only be used in the index.html and not the flutter_bootstrap.js file itself.

Write a custom bootstrap script

#

Any custom flutter_bootstrap.js script needs to have three components in order to successfully start your Flutter app:

  • A {{flutter_js}} token, to make _flutter.loader available.
  • A {{flutter_build_config}} token, which provides information about the build to the FlutterLoader needed to start your app.
  • A call to _flutter.loader.load(), which actually starts the app.

The most basic flutter_bootstrap.js file would look something like this:

js
{{flutter_js}}
{{flutter_build_config}}
​
_flutter.loader.load();

Customize the Flutter loader

#

The _flutter.loader.load() JavaScript API can be invoked with optional arguments to customize initialization behavior:

NameDescriptionJS type
config The Flutter configuration of your app. Object
onEntrypointLoaded The function called when the engine is ready to be initialized. Receives an engineInitializer object as its only parameter. Function

The config argument is an object that accepts the following optional fields:

App embedding, URLs, and debugging

#
NameDescriptionJS type
assetBase Base URL for the app's assets directory when loading from another domain, subdirectory, or CDN (refer to Serve assets from a CDN or self-hosted origin ). string
debugShowSemanticsNodes Visibly renders the semantics tree onscreen for accessibility debugging. boolean
entrypointBaseUrl Base URL for the Flutter app's compiled entrypoint. Defaults to "/". string
fontFallbackBaseUrl Base URL for fallback fonts when bundled fonts lack glyphs. Defaults to "https://fonts.gstatic.com/s/" . string
hostElement HTML element into which Flutter renders a single-view app (refer to Add Flutter to any web application ). When omitted, Flutter renders across the full page. HTMLElement
multiViewEnabled Enables multi-view mode for dynamically adding and removing embedded views (refer to Embedded mode ). boolean
nonce Content Security Policy (CSP) nonce applied to inline scripts and styles created by the engine. string

WebAssembly and build selection

#
NameDescriptionJS type
forceSingleThreadedSkwasm Forces single-threaded WebAssembly rendering when WebAssembly is selected at runtime (for example, when SharedArrayBuffer or COOP and COEP headers are unavailable). Defaults to false . boolean
renderer Forces the renderer to 'canvaskit' or 'skwasm'. string
suppressMultithreadingWarning Suppresses the console warning logged when WebAssembly runs single-threaded because COOP and COEP headers are absent. boolean
verboseBuildSelection Logs console.warn diagnostics explaining why each candidate build in _flutter.buildConfig.builds was selected or skipped. boolean
wasmAllowList Browser engine allowlist ( { blink, webkit, gecko, unknown } ) controlling which engines run the WebAssembly build (refer to Support for WebAssembly ). Defaults to { blink: true, gecko: false, webkit: false, unknown: false } . Object
wasmDeferredModulesLoader Custom loader callback (moduleNames, onModuleLoaded) => Promise<void> for fetching deferred .wasm modules when --enable-wasm-deferred-loading is enabled (refer to Serve assets from a CDN or self-hosted origin ). onModuleLoaded accepts (moduleName: string, module: Response | Promise<Response> | ArrayBuffer) => Promise<void> . Function

CanvasKit options

#
NameDescriptionJS type
canvasKitBaseUrl Base URL from which canvaskit.wasm and rendering engine files are downloaded. string
canvasKitForceCpuOnly Forces CPU-only rendering in CanvasKit without WebGL. boolean
canvasKitMaximumSurfaces Maximum number of overlay surfaces that the CanvasKit renderer can allocate. number
canvasKitVariant CanvasKit build to download: 'auto' (default, selects the optimal build), 'full' (all browsers), or 'chromium' (smaller build for Chromium-based browsers only). string

Example usage

#
js
_flutter.loader.load({
  config: {
    forceSingleThreadedSkwasm: true,
    wasmAllowList: {
      blink: true,
      webkit: true,
      gecko: true,
    },
  },
});

Example: Customize Flutter configuration based on URL query parameters

#

The following example shows a custom flutter_bootstrap.js that enables single-threaded mode when a force_st query parameter is present in the URL:

js
{{flutter_js}}
{{flutter_build_config}}
​
const searchParams = new URLSearchParams(window.location.search);
const forceSt = searchParams.has('force_st');
const userConfig = forceSt ? { forceSingleThreadedSkwasm: true } : {};
_flutter.loader.load({
  config: userConfig,
});

This script evaluates the URLSearchParams of the page to determine whether the user passed a force_st query parameter and configures the app accordingly.

The onEntrypointLoaded callback

#

You can also pass an onEntrypointLoaded callback into the load API in order to perform custom logic at different parts of the initialization process. The initialization process is split into the following stages:

Loading the entrypoint script

The load function calls the onEntrypointLoaded callback once the main entrypoint script has been downloaded and run by the browser. Flutter also calls onEntrypointLoaded on every hot restart during development.

Initializing the Flutter engine

The onEntrypointLoaded callback receives an engine initializer object as its only parameter. Use the engine initializer initializeEngine() function to set the run-time configuration, like multiViewEnabled: true, and start the Flutter web engine.

Running the app

The initializeEngine() function returns a Promise that resolves with an app runner object. The app runner has a single method, runApp(), that runs the Flutter app.

Adding views to (or removing views from) an app

The runApp() method returns a flutter app object. In multi-view mode, the addView and removeView methods can be used to manage app views from the host app. To learn more, check out Embedded mode.

Example: Display a progress indicator

#

To give the user of your application feedback during the initialization process, use the hooks provided for each stage to update the DOM:

js
{{flutter_js}}
{{flutter_build_config}}
​
const loading = document.createElement('div');
document.body.appendChild(loading);
loading.textContent = "Loading Entrypoint...";
_flutter.loader.load({
  onEntrypointLoaded: async function(engineInitializer) {
    loading.textContent = "Initializing engine...";
    // If you have a `config`, pass it here. The config given to `load()`
    // is not forwarded when you supply your own `onEntrypointLoaded`.
    const appRunner = await engineInitializer.initializeEngine();
​
    loading.textContent = "Running app...";
    await appRunner.runApp();
  }
});

Common warnings

#

This section describes common web build and initialization warnings and how to resolve them.

Service worker deprecation

#

If you experience a warning similar to the following during flutter build web:

Warning: In index.html:37: Flutter's service worker is deprecated and will be removed in a future Flutter release.
See https://github.com/flutter/flutter/issues/156910 for more details.

Remove legacy service worker variables, registration calls, and serviceWorkerSettings from your web/index.html or custom web/flutter_bootstrap.js file:

js
// Remove legacy serviceWorkerVersion declarations:
var serviceWorkerVersion = null;
const serviceWorkerVersion = null;
​
// Remove legacy flutter_service_worker.js registration calls:
navigator.serviceWorker.register('flutter_service_worker.js');
​
// Remove serviceWorkerSettings from _flutter.loader.load():
_flutter.loader.load({
  serviceWorkerSettings: {
    serviceWorkerVersion: {{flutter_service_worker_version}},
  },
});

If your app requires a custom service worker, refer to the Web FAQ and Web content hashing (precache_manifest.json).

FlutterLoader.loadEntrypoint deprecation

#

If you experience a warning similar to the following:

Warning: In index.html:40: "FlutterLoader.loadEntrypoint" is deprecated.
Use "FlutterLoader.load" instead.

This warning occurs when an older web/index.html file uses _flutter.loader.loadEntrypoint() instead of _flutter.loader.load(). The CLI message references the FlutterLoader interface, which JavaScript code accesses through _flutter.loader.

If your app uses the default initialization and doesn't require custom bootstrapping, replace the legacy script block in web/index.html with the standard script tag:

web/index.html
html
<script src="flutter_bootstrap.js" async></script>

If you customized your initialization logic, update your bootstrap code in web/index.html (or a custom web/flutter_bootstrap.js file) to call _flutter.loader.load() instead:

js
_flutter.loader.load({
  onEntrypointLoaded: async function(engineInitializer) {
    const appRunner = await engineInitializer.initializeEngine();
    await appRunner.runApp();
  }
});

To review an example that updates DOM elements during startup, refer to the progress indicator example.