Skip to content
Blog

dart2js: How Dart Compiles to JavaScript for Flutter Web

Before WebAssembly, Flutter Web compiled Dart through dart2js. Learn how the Dart-to-JavaScript compiler works, what it costs, and where it still fits now that Wasm is the default target.

Published on • October 21, 2026

AI Assistant

WebAssembly may be Flutter Web’s headline compilation target now, but the path that got Flutter on the web at all runs through dart2js — the ahead-of-time compiler that turns Dart into JavaScript. Understanding how it works explains both why early Flutter Web felt slow and why the compiler still matters for the broad compatibility it provides.

Source: Dart — compilation and dart2js and the Flutter Web documentation, The Dart Team.

What dart2js does

dart2js is an ahead-of-time compiler: it takes Dart source and emits a single, self-contained JavaScript bundle that runs in any modern browser with no Dart runtime to install. To do that it has to bridge a real semantic gap. Dart’s type system, null safety, async/await semantics, isolates model, and dart: library surface do not map one-to-one onto JavaScript, so the compiler emits support code alongside your program to reproduce Dart’s behavior faithfully.

That fidelity is the achievement and the cost in one. The output behaves like Dart — but reproducing Dart on top of a dynamically typed language takes runtime scaffolding that adds weight and work for the JS engine.

Where the performance went

The performance characteristics of dart2js output follow from the target. JavaScript engines optimize aggressively through just-in-time compilation, but that warmup means performance varies with usage patterns and engine state. Dart’s type information, which a native compiler can erase into machine instructions, largely becomes a hint the JS engine may or may not exploit. The practical results for early Flutter Web were slower startup, higher memory use, and frame rates that could not match native mobile — tolerable for simple screens, frustrating for complex dashboards and animation-heavy UIs.

This is precisely the gap WebAssembly addresses. Where dart2js compiles to a high-level, JIT-optimized language, Wasm compiles to a binary format executing near native speed with a predictable model. That contrast is why the ecosystem moved: not because dart2js is broken, but because the ceiling on a JavaScript target is lower for the kind of tight rendering loops Flutter depends on.

Where dart2js still fits

Despite the shift, dart2js is not obsolete, and there are real reasons it endures:

  • Maximum compatibility. JavaScript runs everywhere, instantly, with no instantiation step. For broad reach with zero friction, it remains the safest target.
  • The Dart web ecosystem. Server-side and pure-Dart web frameworks — Jaspr among them — rely on the Dart-to-JavaScript path, and a large body of Dart web code compiles through dart2js.
  • Debugging familiarity. Stepping through recognizable JavaScript is often easier for web developers than reading Wasm-adjacent output.

For Flutter specifically, the default has moved toward WebAssembly, but dart2js remains the fallback and the compatibility story.

The practical takeaway

If you are shipping Flutter Web today, the guidance is straightforward: reach for WebAssembly by default when you want performance and your target browsers support it, and understand dart2js as the compatibility path underneath. Knowing that dart2js reproduces Dart semantics in a JIT-optimized, dynamically typed target is enough to explain every performance difference you will observe between a Wasm build and a JS build of the same app — and to reason about which one a given deployment actually needs.

Key takeaways

dart2js is Dart’s ahead-of-time compiler to JavaScript: it emits a self-contained JS bundle faithful to Dart’s semantics — types, null safety, async — at the cost of runtime support code and the performance ceiling of a JIT-optimized, dynamically typed target. That ceiling is why Flutter Web’s default compilation moved to WebAssembly for demanding UIs. dart2js endures where compatibility and the broader Dart web ecosystem matter, and it remains the fallback beneath the Wasm default.

Further reading