You can compile Dart and Flutter web applications to
WebAssembly (dart2wasm) as a high-performance production
alternative to JavaScript (dart2js). Compiling to WebAssembly reduces initial
page load times, eliminates main-thread JavaScript just-in-time (JIT)
compilation pauses, and delivers consistent frame rendering in modern browsers.
Compile your web app to Wasm
#
Use the dart compile wasm command to compile a Dart web
app to a WebAssembly module. For a full list of compiler flags, refer to
Compiler optimization levels and flags
or run
dart compile wasm --help.
To compile and run a Dart web app with Wasm, follow these steps:
-
Create a web app and switch to its directory:
$ dart create -t web mywebapp $ cd mywebappThe template creates a small web app that uses
package:web, which is required to run Wasm. Existing web apps must migrate fromdart:htmltopackage:web. -
Compile the app to Wasm into a
siteoutput directory:$ dart compile wasm -O2 web/main.dart -o site/main.wasmThis command produces
site/main.wasm, the companion JavaScript runtimesite/main.mjs, andsite/main.wasm.map. -
Copy over the static web files:
$ cp web/index.html web/styles.css site/ -
Because
index.htmlloadsmain.dart.js, createsite/main.dart.jsto fetchsite/main.wasmand import the generatedsite/main.mjsruntime in parallel:site/main.dart.jsjs(async function () { const wasmPromise = fetch('main.wasm'); const { compileStreaming } = await import('./main.mjs'); const app = await compileStreaming(wasmPromise); const instantiatedApp = await app.instantiate({}); instantiatedApp.invokeMain(); })(); -
Serve the
sitedirectory by using a local HTTP server such asdhttpd:$ dart run dhttpd@ --path site
You can also explore this small sandbox example.
WebAssembly support and requirements
#When compiling Dart to WebAssembly, keep the following browser, interop, and platform requirements in mind:
-
WebAssembly standards and browser compatibility: The
dart2wasmcompiler targets three standardized WebAssembly proposals: WebAssembly Garbage Collection (WasmGC), JS String Builtins (wasm:js-string), and Phase 4 Exception Handling (thetry_tableandexnrefinstructions). Running compiled modules in a browser requires one of the following minimum browser versions:- Chrome or Edge 137+
- Safari 26.2+ (macOS and iOS)
- Firefox 134+ (or 147+ for Flutter web)
For additional browser compatibility details, refer to the Flutter Wasm documentation.
-
Target environments and standalone mode: By default, compiled Wasm output targets JavaScript environments (such as browsers) and generates a companion
<name>.mjsruntime file. To compile a standalone WebAssembly module for non-web runtimes such as Wasmtime 39+ (with the-W gc,exceptions,function-references=yflag), pass the--standaloneflag todart compile wasm. Standalone mode disallows thedart:js_interoplibrary and the--enable-deferred-loadingflag. -
JavaScript interop: Compiling to Wasm supports only Dart's next-generation JS interop mechanism (
dart:js_interopandpackage:web). -
Build tooling: The
webdevtool doesn't support Wasm compilation (webdev serveorwebdev build). Instead, follow the steps in Compile your web app to Wasm.
Supported packages
#
To find Wasm-compatible packages, use the wasm-ready
filter on
pub.dev.
A package is wasm-ready when it doesn't import legacy web or interop
libraries such as dart:html, dart:js, or package:js. Refer to the
past JS interop page
for the full list of disallowed
libraries.
Conditional imports and SIMD support
#-
Conditional imports (
dart.library.isolate): When compiling withdart2wasm,dart.library.isolateevaluates tofalsein conditional imports (if (dart.library.isolate)), matching the behavior ofdart2jsandddc. -
128-bit Wasm SIMD (
v128): Indart2wasm,dart:typed_dataSIMD types (Int32x4,Float32x4,Float64x2,Int32x4List,Float32x4List, andFloat64x2List) are backed by native WebAssembly 128-bitv128SIMD instructions.
Compiler optimization levels and flags
#
Tune dart compile wasm flags to balance compilation speed during development
against smaller binary size and faster execution in production builds:
$ dart compile wasm -O2 web/main.dart -o site/main.wasm
Optimization levels reference
#
The -O0 through -O4 optimization levels enable progressively more
aggressive compiler passes:
| Flag | Binaryen (wasm-opt) |
Function inlining | Minify runtime names (--minify) and omit error details |
Omit implicit type checks | Omit index bounds checks |
|---|---|---|---|---|---|
-O0 |
Disabled | Disabled | Disabled | Disabled | Disabled |
-O1 (default) |
Enabled | Enabled | Disabled | Disabled | Disabled |
-O2 |
Enabled | Enabled | Enabled | Disabled | Disabled |
-O3 |
Enabled | Enabled | Enabled | Enabled | Disabled |
-O4 |
Enabled | Enabled | Enabled | Enabled | Enabled |
For most production builds, use the -O2 flag. This level enables full size
and speed optimizations (including wasm-opt, function inlining, and
minification) while preserving standard Dart runtime semantics, type checks,
and bounds checks.
Additional production CLI flags
#
Use the following flags with dart compile wasm to
customize output symbols, source maps, module splitting, and compile-time
configuration:
| Flag | Default | Description |
|---|---|---|
--minify |
-O2 and higher |
Minifies runtime names (such as runtimeType.toString()). |
--[no-]strip-wasm |
Enabled |
Strips static symbol names from the
.wasm
binary to reduce download size. Pass
--no-strip-wasm
when
profiling in Chrome DevTools
.
|
--[no-]source-maps |
Enabled |
Generates
<output>.wasm.map
to map Wasm instruction offsets back to Dart source files and line numbers.
|
--[no-]enable-deferred-loading |
Disabled |
Splits
deferred as
imports into separate
<name>_module<id>.wasm
modules loaded on demand.
|
--standalone |
Disabled |
Emits a standalone Wasm module without JavaScript interop for non-web runtimes such as Wasmtime (disallows
dart:js_interop
and
--enable-deferred-loading
).
|
-D<key>=<value> or --define |
None |
Defines compile-time environment declarations read by
String.fromEnvironment
,
int.fromEnvironment
, or
bool.fromEnvironment
.
|
Detect Wasm compilation in Dart code
#
When compiling with dart2wasm, the compiler automatically defines
dart.tool.dart2wasm as true in the compile-time environment:
const bool isRunningAsWasm = bool.fromEnvironment('dart.tool.dart2wasm');
Deferred loading
#
By default, compiled applications load as a single .wasm module. For large
applications, pass --enable-deferred-loading to split
deferred libraries into separate
<name>_module<id>.wasm
files:
$ dart compile wasm -O2 --enable-deferred-loading web/main.dart -o site/main.wasm
When you enable deferred loading, your application loader must provide a
loadDeferredModules callback to app.instantiate() that fetches and loads
the deferred module bytes:
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();
How dart2wasm works
#
The dart2wasm ahead-of-time (AOT) compiler translates Dart source code into
compact WebAssembly bytecode that integrates directly with the browser's native
garbage collector and string runtime.
The dart2wasm AOT compilation pipeline
#
When you run dart compile wasm, the dart2wasm compiler executes four
sequential phases:
-
cfe(Common Front End): Parses Dart source code, enforces sound null safety, and applies modular kernel transformations into a.dillkernel abstract syntax tree (AST). -
tfa(Type Flow Analysis): Performs closed-world whole-program analysis, tree-shaking unreachable code, devirtualizing method calls, and inferring concrete types and unboxing opportunities. -
codegen(Wasm code generation): Translates the optimized Dart kernel into WebAssembly instructions and WasmGC struct and array type definitions, emitting<name>.wasm, the<name>.mjsJavaScript runtime loader, and<name>.wasm.map. -
opt(Binaryen optimization): Runswasm-opt(at-O1and higher) to optimize Wasm instruction sequences and shrink binary size.
WebAssembly standards used by Dart
#
The dart2wasm compiler targets standardized WebAssembly proposals to
minimize binary size and runtime overhead:
-
WebAssembly Garbage Collection (WasmGC):
Maps Dart objects, classes, and collections directly to native
garbage-collected heap structures managed by the browser engine (such as V8
in Chrome). Because
dart2wasmdoesn't ship a custom linear-memory allocator or duplicate garbage collector alongside the browser's garbage collector, modules are smaller and avoid cross-heap memory cycles. -
JS String Builtins (
wasm:js-string): Lets Wasm modules use native JavaScript string operations and pass strings across the JavaScript and Wasm boundary without expensive UTF-8 or UTF-16 transcoding copies. -
Exception Handling (Phase 4):
Uses native WebAssembly exception tags (
try_tableandexnref) for low-overheadtryandcatchhandling and stack trace generation.
Performance benefits over JavaScript
#
Compiling to WebAssembly improves startup latency and frame consistency
compared to compiling to JavaScript (dart2js):
- Eliminates JS parse and JIT evaluation bottlenecks: Large JavaScript bundles require the browser to download text, parse source tokens into an AST, and run multi-tier JIT compilation on the main thread before interactive rendering stabilizes.
-
Streaming background compilation:
Browsers compile compact binary
.wasmbytecode across background threads while the network response streams (WebAssembly.compileStreaming). - Predictable execution from the first frame: Closed-world AOT compilation and static dispatch tables deliver consistent execution times without waiting for JIT warm-up or suffering deoptimization bailouts.
Profile Wasm performance and footprint
#
Before deploying,
profile your compiled app in Chrome DevTools
to verify Core Web Vitals
and inspect your .wasm download and memory footprint.
Measure Core Web Vitals (LCP, INP, and CLS)
#
By default, dart compile wasm strips the WebAssembly name custom section,
so functions appear as numeric indices in CPU traces.
To keep readable Dart function and class names
without disabling production optimizations,
compile with the -O2 and --no-strip-wasm flags:
$ dart compile wasm -O2 --no-strip-wasm web/main.dart -o site/main.wasm
Record a trace in the Chrome DevTools Performance panel
to evaluate Core Web Vitals and verify that
main.mjs and main.wasm
fetch in parallel without main-thread long tasks or frequent Wasm-to-JS
interop calls. For general browser debugging setup, refer to
Debugging Dart web apps.
Inspect Wasm module size and memory
#Use the Chrome DevTools Network and Memory panels to check wire size and runtime heap usage:
-
Network transfer size:
Compile a stripped production build (
dart compile wasm -O2, without the--no-strip-wasmflag) and use the Chrome DevTools Network panel to compare compressed transfer size (brorgzip) against uncompressed size and confirm theContent-Type: application/wasmresponse header. If initial.wasmsize delays load, split routes with the--enable-deferred-loadingflag (refer to Deferred loading). -
Runtime WasmGC heap:
Because
dart2wasmcompiles Dart objects to native WasmGC structs and arrays managed by V8's garbage collector (rather than an opaque linear-memoryArrayBuffer), live Dart instances appear directly in JavaScript heap profiles. Compile with the--no-strip-wasmflag so WasmGC type and field names remain readable when recording heap snapshots.
Deploy Wasm in production
#
To get the full startup and runtime benefits of WebAssembly in production,
configure your web server and release pipeline to stream, compress, and cache
.wasm modules and provide a JavaScript fallback for older browsers. Refer to
Serve WebAssembly in production
in the web deployment guide
for complete instructions on the following tasks:
- Serving
.wasmfiles with theContent-Type: application/wasmheader. - Preloading
.mjsand.wasmassets in parallel for streaming compilation. - Pre-compressing
.wasmbinaries with Brotli (brotli -q 11) and Gzip. -
Configuring content-hashed immutable caching, atomic
.mjsand.wasmdeployments, and V8 Wasm code caching. - Providing a
dart2jsfallback pathway for older browsers.
Unless stated otherwise, the documentation on this site reflects Dart 3.14.0. Page last updated on 2026-11-10. View source or report an issue.