Skip to main content

WebAssembly (Wasm) compilation

Learn how to compile your Dart web app to WebAssembly.

You can compile Dart and Flutter web applications to WebAssembly (dart2wasm) as an alternative to JavaScript for production builds.

WebAssembly support

#

When compiling Dart to WebAssembly, keep the following requirements and platform behaviors in mind:

  1. dart2wasm targets three standardized WebAssembly proposals: WasmGC (Garbage Collection), JS String Builtins (wasm:js-string), and Phase 4 Exception Handling (try_table and exnref). Running compiled modules in a browser requires at least:

    • Chrome or Edge 137+
    • Safari 26.2+ (macOS and iOS)
    • Firefox 134+ (or 147+ for Flutter web)

    For more browser compatibility details, see the Flutter Wasm documentation.

  2. By default, compiled Wasm output targets JavaScript environments (such as browsers) and generates a companion <name>.mjs runtime file. To compile a standalone WebAssembly module for non-web runtimes such as Wasmtime 39+ (using -W gc,exceptions,function-references=y), pass --standalone to dart compile wasm. When --standalone is set, dart:js_interop is disallowed.

  3. Only Dart's next-gen JS interop mechanism is supported when compiling to Wasm.

  4. The webdev tool doesn't currently support Wasm compilation (webdev serve or webdev build). Instead, follow the steps in Compiling your web app to Wasm.

Deferred loading

#

By default, compiled applications do not use deferred loading. Deferred loading in Wasm is experimental. To enable it, pass the --enable-deferred-loading flag:

dart compile wasm --enable-deferred-loading ...

Enabling deferred loading requires your app loader to supply a callback that loads the deferred module bytes:

js
import { compileStreaming } from './main.mjs';
​
const app = await compileStreaming(fetch('main.wasm')); // or compile(...)
const instantiatedApp = await app.instantiate({}, {
  loadDeferredModules: (modules, handleModuleByteSource) => {
    return Promise.all(
      modules.map((m) => fetch(m).then((r) => handleModuleByteSource(m, r)))
    );
  },
});
instantiatedApp.invokeMain();

Conditional imports and SIMD support

#
  • Conditional imports (dart.library.isolate): When compiling with dart2wasm, dart.library.isolate evaluates to false in conditional imports (if (dart.library.isolate)), matching the behavior of dart2js and ddc.
  • 128-bit Wasm SIMD (v128): In dart2wasm, dart:typed_data SIMD types (Int32x4, Float32x4, Float64x2, Int32x4List, Float32x4List, and Float64x2List) are backed by native WebAssembly 128-bit v128 SIMD instructions.

Supported packages

#

To find Wasm-compatible packages, use the wasm-ready filter on pub.dev.

A package is "wasm-ready" if it doesn't import non-Wasm compliant libraries such as dart:html or dart:js. You can find the full list of disallowed libraries on the JS interop page.

Compiling your web app to Wasm

#

Use the dart compile wasm command in the dart CLI to invoke the Wasm compiler in Dart and Flutter:

dart help compile wasm -v
Compile Dart to a WebAssembly/WasmGC module.

Usage: dart compile wasm [arguments] <dart entry point>
-h, --help                              Print this usage information.
-o, --output                            Write the output to <file name>.
                                        This can be an absolute or relative path.
-v, --verbose                           Print debug output during compilation
    --enable-asserts                    Enable assert statements.
-O, --optimization-level=<level>        Controls optimizations that can help reduce
                                        code-size and improve performance of the
                                        generated code.
                                        [0, 1 (default), 2, 3, 4]
    --[no-]minify                       Minify names that are needed at runtime (such
                                        as class names). Affects e.g.
                                        `<obj>.runtimeType.toString()`). If passed,
                                        this takes precedence over the
                                        optimization-level option.
    --[no-]strip-wasm                   Whether to strip the resulting wasm file of
                                        static symbol names.
                                        (defaults to on)
    --[no-]source-maps                  Generate a source map file.
                                        (defaults to on)
    --[no-]enable-deferred-loading      Emit multiple modules based on the Dart
                                        program's deferred import graph.
    --standalone                        Compile to a WebAssembly module without
                                        JavaScript interop. Dart-specific host
                                        imports are necessary to load these modules.
-D, --define=<key=value>                Define an environment declaration. To specify
                                        multiple declarations, use multiple options
                                        or use commas to separate key-value pairs.
                                        For example: dart compile wasm -Da=1,b=2
                                        main.dart

To compile and run a Dart web app with Wasm, follow these steps:

  1. Create a web app and switch to its directory:

    dart create -t web mywebapp
    cd mywebapp
    

    The template creates a small web app using package:web, which is necessary to run Wasm. Make sure your web apps are migrated from dart:html to package:web.

  2. Compile the app to Wasm into a site output directory:

    dart compile wasm -O2 web/main.dart -o site/main.wasm
    

    This produces site/main.wasm, the companion JavaScript runtime site/main.mjs, and site/main.wasm.map.

  3. Copy over the static web files:

    cp web/index.html web/styles.css site/
    
  4. Because index.html loads main.dart.js, create site/main.dart.js to import the generated site/main.mjs runtime and instantiate site/main.wasm:

    site/main.dart.js
    js
    (async function () {
      const { compileStreaming } = await import('./main.mjs');
      const app = await compileStreaming(fetch('main.wasm'));
      const instantiatedApp = await app.instantiate({});
      instantiatedApp.invokeMain();
    })();
    
  5. Serve the site directory using dhttpd:

    dart run dhttpd@ --path site
    

You can also try out this small sandbox example.