Skip to main content
The dart2js compiler translates Dart code into optimized JavaScript for deployment in web browsers. It’s designed for production use, offering aggressive optimizations including tree-shaking, minification, and deferred loading.

Overview

dart2js is a whole-program compiler that performs global analysis and optimization to produce fast, compact JavaScript output. Unlike dartdevc, which prioritizes development speed, dart2js focuses on production-ready output with minimal file size and maximum runtime performance.

Architecture

The compiler operates in several phases:
  1. Common Front-End - Parsing, type checking, and Kernel AST generation
  2. Tree-Shake and Create World - Determine reachable code using Rapid Type Analysis (RTA)
  3. Global Analysis - Type inference and data flow analysis across method boundaries
  4. Code Generation - Build SSA graph, optimize, and emit JavaScript
  5. Link Tree-Shake - Second round of tree-shaking after optimizations
  6. Emit JavaScript - Assemble final program with minified names

Basic Usage

Command Line

Compile a Dart application to JavaScript:
dart compile js -o output.js input.dart
With optimizations:
dart compile js -O2 -o output.js input.dart

Common Options

OptionDescription
-o, --output=<file>Output file path
-O0, -O1, -O2, -O3, -O4Optimization level (default: O2)
--minifyMinify output (enabled by default in production)
--no-minifyDisable minification
--no-source-mapsDon’t generate source maps
-D<name>=<value>Define environment variable

Optimization Levels

Minimal optimization for debugging:
dart compile js -O0 -o debug.js app.dart
  • Fastest compilation
  • Largest output size
  • Best for debugging
  • Preserves code structure

Advanced Features

Deferred Loading

Split your application into smaller chunks that load on demand:
// main.dart
import 'heavy_library.dart' deferred as heavy;

Future<void> loadFeature() async {
  await heavy.loadLibrary();
  heavy.expensiveOperation();
}
Compile with deferred loading:
dart compile js -o app.js main.dart
This generates:
  • app.js - Main bundle
  • app.js_1.part.js - Deferred chunk for heavy_library

Source Maps

Generate source maps for debugging:
dart compile js -o app.js --source-maps main.dart
This produces:
  • app.js - Compiled JavaScript
  • app.js.map - Source map for debugging

Environment Variables

Define compile-time constants:
dart compile js -DAPI_URL=https://api.example.com -o app.js main.dart
const apiUrl = String.fromEnvironment('API_URL', defaultValue: 'http://localhost');

Compiler Pragmas

dart2js supports pragmas to control compilation behavior:

Inline Control

// Force inlining
@pragma('dart2js:tryInline')
void frequentFunction() {
  // Hot path code
}

// Prevent inlining
@pragma('dart2js:noInline')
void debugOnlyFunction() {
  // Code that should not be inlined
}

// Disable inlining within a function
@pragma('dart2js:disable-inlining')
void noInlineCallsHere() {
  // Calls inside won't be inlined
}

Runtime Checks

// Trust casts (unsafe)
@pragma('dart2js:as:trust')
T unsafeCast<T>(Object? o) => o as T;

// Trust downcasts
@pragma('dart2js:downcast:trust')
void trustImplicitDowncasts(dynamic value) {
  String s = value; // No runtime check
}

// Trust late field initialization
@pragma('dart2js:late:trust')
late final String cachedValue;

Optimization Hints

// Allow common subexpression elimination
@pragma('dart2js:allow-cse')
external String getConstantValue();

// Allow dead code elimination
@pragma('dart2js:allow-dce')
external void logDebugInfo();
See the complete pragma documentation for all available annotations.

Performance Tips

Tree-Shaking

dart2js automatically removes unused code. Help it by:
// Bad: Imports everything
import 'package:huge_library/huge_library.dart';

// Good: Import only what you need
import 'package:huge_library/specific_module.dart';

Type Annotations

Provide types for better optimization:
// Less optimizable
var list = [];

// Better
final List<int> list = [];

Avoid Dynamic

Dynamic calls prevent optimization:
// Slow: dynamic call
void process(dynamic obj) {
  obj.method(); // Can't be optimized
}

// Fast: typed call
void process(MyClass obj) {
  obj.method(); // Can be inlined and optimized
}

Debugging Compiled Output

Analyze Output Size

Use dump-info to understand code size:
dart compile js --dump-info -o app.js main.dart
dart run dart2js_info:info_explorer app.js.info.json

Readable Output

Generate more readable JavaScript:
dart compile js -O0 --no-minify -o readable.js main.dart

Migration from dart2js Command

Legacy dart2js command is deprecated. Use dart compile js instead:
dart2js -O2 --out=app.js main.dart

Limitations

  • No dart:io - JavaScript runtime doesn’t support file system operations
  • No dart:mirrors - Reflection is not supported for code size reasons
  • No dart:ffi - Foreign Function Interface unavailable in JavaScript
  • Integer precision - JavaScript numbers are 64-bit floats; use BigInt for large integers

Build docs developers (and LLMs) love