Dart — Reference
Source: https://dart.dev/guides
Dart
- Created: 2011 by Lars Bak and Kasper Lund at Google (1.0 in 2013; Dart 2 in 2018 made type system sound; Dart 3 in 2023 made null safety mandatory and added records + patterns)
- Latest stable: 3.11 (current as of 2026-05; the Dart team ships a stable release roughly every 3 months — verify exact patch on https://dart.dev/get-dart)
- Paradigms: Multi-paradigm — object-oriented (everything is an object, including
nulland functions; classes only — no free-standing structs), imperative, functional-leaning (first-class functions, closures, records, sealed/pattern matching since 3.0) - Typing: Static, strong, sound null safety (since 2.12, mandatory since 3.0); type inference; mixin-based composition; generics with bounded type parameters and reified runtime types
- Memory: Garbage-collected — generational, parallel scavenger for new-gen + concurrent mark-sweep for old-gen; isolates have separate heaps (no shared mutable state across isolates)
- Compilation: JIT for development (fast iteration, hot reload,
dart run); AOT for production (dart compile exe/aot-snapshot); dart2js + dart2wasm for the web; Flutter targets iOS/Android/desktop/web from one codebase - Primary domains: Flutter (the dominant use — cross-platform mobile/desktop/web/embedded UI), CLI tools (Google internal + community), server-side via
dart_frog/shelf, devops / build tooling - Official docs: https://dart.dev/guides
At a glance
- Steward: Google (Dart team, originally with the V8/Strongtalk pedigree). The language and tooling are open source under BSD-3.
- Dart’s killer app is Flutter — without Flutter, Dart would be a niche language. Flutter went stable in 2018 and has become the de-facto cross-platform UI toolkit.
- Release cadence: ~quarterly stable releases (channels:
stable,beta,dev,main). Major versions follow Flutter’s needs. - Flutter releases bundle a Dart SDK; using Flutter you typically don’t install Dart separately.
- Reference impl: the Dart VM (in C++; ARM64/x64 native + WASM); also dart2js (transpiler to JS), dart2wasm (transpiler to Wasm GC).
- License: BSD-3-Clause.
Getting started
-
Install: Pick one — Homebrew (
brew tap dart-lang/dart && brew install dart), Chocolatey on Windows (choco install dart-sdk), apt on Debian/Ubuntu (Google APT repo), Docker (google/dart), or just install Flutter which bundles the Dart SDK. (https://dart.dev/get-dart) -
Version manager:
fvm(Flutter Version Management) is the dominant choice for Flutter+Dart project pinning;purois a newer alternative; asdf-dart for asdf users. Dart itself doesn’t ship a first-party multi-version switcher. -
Hello world (
hello.dart):void main() { print('Hello, world!'); }Run:
dart run hello.dart(JIT) ordart compile exe hello.dart -o hello && ./hello(AOT). -
Project layout (
dart create):pubspec.yaml(manifest),pubspec.lock,lib/<name>.dart(public API),lib/src/(private),bin/<entrypoint>.dart(executable apps),test/,analysis_options.yaml(lints). Flutter projects addandroid/,ios/,lib/main.dart,web/. -
Package manager:
pub(built into the SDK; commands surface asdart pubandflutter pub). Public registry is pub.dev. Versions follow caret semver (^3.0.0means>=3.0.0 <4.0.0). -
REPL: Dart historically lacked a REPL. DartPad (https://dartpad.dev) is the official browser playground.
dart run --enable-vm-service+ the observatory CLI is the closest thing to interactive debugging. Community projects (interactive_dart) exist but aren’t standard.
Basics
- Types/literals:
int(64-bit on VM, JS-numeric on web),double(IEEE-754),num(supertype of both),String,bool,List<T>,Set<T>,Map<K, V>,Symbol,Runes(Unicode codepoints),Future<T>,Stream<T>,Record(since 3.0 —(int, String)or named({int x, int y})). Numeric literals:1_000_000(since 2.13),0xFF,1.5e3. Nochartype — use single-charStringorintcodepoint. - Variables:
var(inferred type),final(single-assignment, runtime),const(compile-time constant),late(late-init non-null), explicit type (int x = 1). Top-level vars allowed. - Scoping: Lexical, block-scoped. Closures capture by reference.
librarydirective (now mostly implicit) groups multiple files. - Control flow:
if/else(statement only — no ternary asifexpression, butcond ? a : bworks);switch(statement and expression since 3.0, with patterns —switch (point) { case (0, 0) => 'origin'; case (var x, 0) => 'on x-axis'; });for/for-in/while/do-while;try/catch/on/finally. Patterns and records (3.0): destructuring (var (x, y) = point;), exhaustive switch on sealed hierarchies. - Functions:
int add(int a, int b) => a + b;(arrow body) orint add(int a, int b) { return a + b; }. Optional positional[], optional named{}, required namedrequired int x. First-class — can be assigned, passed, returned. Anonymous:(x) => x * 2. Tear-offs:list.forEach(print). - Strings: Single or double quotes;
'Hello $name'and'Hello ${user.name}'interpolation; rawr'\n'; multi-line'''...'''or"""...""". Strings are UTF-16 code unit sequences under the hood —.codeUnits(UTF-16),.runes(Unicode codepoints). - Collections:
List(growable by default;List.filled(n, 0, growable: false)for fixed),Set({1, 2, 3}literal),Map({'a': 1}literal). Collection-if and collection-for in literals:[for (var x in xs) if (x.isEven) x * 2]. Spread:[...a, ...?maybeNull, b].
Intermediate
- Type system depth: generics (
List<int>), bounded type params (T extends Comparable<T>), function types as values (int Function(int, int)), typedef aliases,dynamic(escape hatch — turns off static checks but keeps runtime checks),Object?for “anything nullable”,Never(bottom type — function never returns). Sound null safety means non-nullable types cannot hold null at runtime, eliminating a class of NPE errors. - Modules / libraries: files are libraries by default;
import 'package:foo/foo.dart',import 'dart:io',import 'src/util.dart'. Visibility: leading underscore = library-private (_foo).exportfor re-export. Conditional imports for cross-platform (import 'src/io.dart' if (dart.library.html) 'src/web.dart'). - Error handling:
Exception(recoverable) vsError(programming bug — shouldn’t be caught).throw,try/catchwithon TypeName catch (e, stackTrace),finally,rethrow. Async errors flow throughFuture.catchError/await ... try/catch.StackTraceis first-class. - Concurrency primitives:
Future<T>+async/await— single-threaded event-loop concurrency (like JS). The Dart VM has one event loop per isolate.Stream<T>— async iterables, single-subscription or broadcast;await for,StreamController,StreamTransformer.- Isolates — true parallel workers with separate heaps (no shared memory). Communicate via
SendPort/ReceivePortmessage passing.Isolate.spawnand the higher-levelIsolate.run(since 2.19) for fire-and-forget. Now isolates can shareTransferableTypedDataand (since 3.7) some immutable data without copying. - No native threads / no GIL discussions — Dart simply doesn’t share mutable state across isolates by design.
- I/O:
dart:io(server/CLI/desktop —File,Directory,Socket,HttpClient,Process,Platform,Stdin/Stdout);dart:html(web only — DOM);package:httpfor high-level HTTP;package:diofor batteries-included HTTP. Web targets do not havedart:io. - Stdlib highlights:
dart:core(collections, strings, num),dart:async(Future, Stream, Timer, Zone),dart:collection(LinkedList, Queue, UnmodifiableMapView),dart:convert(json,utf8,base64, custom converters),dart:math(Random, Point, Rectangle, Vector),dart:io,dart:ffi,dart:isolate,dart:typed_data(Uint8List,Float64List— flat numeric buffers),dart:mirrors(limited; see God mode).
Advanced
- Memory/GC: Generational concurrent GC. New-gen uses a parallel scavenger (Cheney-style copying); old-gen uses concurrent mark-sweep with optional compaction. Each isolate has its own heap and its own GC — no stop-the-world across isolates. The VM exposes GC stats via the VM Service Protocol / Observatory. (https://github.com/dart-lang/sdk/blob/main/runtime/docs/gc.md)
- Concurrency deep dive: the event loop runs in two queues — the microtask queue (drained completely between events;
scheduleMicrotask) and the event queue (I/O, timers, isolate messages).awaitschedules a microtask to resume after the awaited Future completes.Zone(runZoned) provides scoped error/print interception — used by Flutter’s framework to catch async errors. (https://dart.dev/articles/archive/zones) - AOT vs JIT:
- JIT (
dart run) — fast startup, full reflection (dart:mirrors), supports hot reload; what Flutterflutter runuses in debug. - AOT (
dart compile exe/flutter build apk --release) — single binary, fast startup, no JIT warmup, nodart:mirrors, tree-shakes aggressively. Slower compile, faster runtime.
- JIT (
- FFI (
dart:ffi): call C ABI directly without writing native plugins.Native<T>()annotations +Pointer<T>+DynamicLibrary.open(...). Supports structs, arrays, callbacks (Dart→C), and (since 3.0) the@Nativeannotation for direct binding generation bypackage:ffigen(which parses.hfiles via libclang). (https://dart.dev/interop/c-interop) - Reflection:
dart:mirrorsexists but is discouraged — incompatible with AOT (it disables tree-shaking, ballooning binary size). Use code generation instead (build_runner+source_gen). Limited runtime type info:runtimeType,is/as,Typeliterals. - Performance tools: DevTools (https://dart.dev/tools/dart-devtools) — full IDE-grade Flutter/Dart profiler with CPU sampler, memory, network, timeline, widget inspector. VM Service Protocol is the underlying JSON-RPC interface (used to be called Observatory).
dart run --observeexposes it. Benchmark harness inpackage:benchmark_harness.
God mode
- Macros (experimental, 3.x preview): static metaprogramming planned to replace much of
build_runnercodegen. Macro authors write Dart code that runs at compile time and emits new declarations. Not stable as of 3.11 — see https://dart.dev/language/macros for status. - Code generation via
build_runner+source_gen: the current metaprogramming story. Annotation processors (json_serializable,freezed,riverpod,drift,injectable,retrofit) generate.g.dartfiles. Rundart run build_runner build(orwatch). Thesource_genpackage gives you aBuilderAPI on top of the analyzer. dart:mirrorscaveats: AOT-incompatible; not available on web (dart2js). Use only in dev tooling, JIT-only servers, or test code. The Flutter framework forbids it.- VM Service Protocol: a stable JSON-RPC interface to a running Dart VM — list isolates, get stack traces, evaluate expressions in scope, sample CPU, get GC events, hot-reload. DevTools is just a fancy client. Spec: https://github.com/dart-lang/sdk/blob/main/runtime/vm/service/service.md
- Hot reload internals: the VM swaps in modified Dart source at runtime, preserving isolate state and existing object instances. Works in JIT mode only. The framework (Flutter) reruns
build()to repaint widgets with the new code. Class-shape changes (adding fields, removing methods) trigger hot restart (full state loss) instead. - Tree shaking: the AOT compiler eliminates unused declarations.
@pragma('vm:entry-point')marks symbols that must be retained (used by FFI callbacks invoked from native code). Mirrors disable tree-shaking entirely. - Isolates internals: each isolate is a separate VM “actor” with its own heap, microtask queue, and event loop. Spawning costs ~ms; messaging is via copying (or transferable typed data for zero-copy).
Isolate.run(2.19+) is a higher-level “do this in a worker, give me back a Future” wrapper. Isolate groups (3.0+) share the JIT cache and code memory. - Flutter engine binding: Flutter is C++ (Skia/Impeller renderer + Dart VM embedder). Dart calls into the engine via FFI-like
dart:uibindings. The widget tree → element tree → render tree pipeline is pure Dart on top. - AOT snapshots:
dart compile aot-snapshotproduces a.aotfile that thedartaotruntimeexecutable runs. Smaller thancompile exe(no embedded runtime). Used by app servers likedart_frog. - Pragmas (
@pragma): undocumented-ish hints to the compiler —vm:entry-point,vm:prefer-inline,vm:never-inline,vm:always-consider-inlining,vm:notify-debugger-on-exception. Listed inruntime/vm/compiler/recognized_methods_list.hof the SDK source. - Wasm GC backend:
dart compile wasmsince 3.4 emits Wasm GC modules — runs in browsers without dart2js intermediate. Smaller, faster startup than dart2js for compute-heavy workloads.
Idioms & style
- Naming:
lowerCamelCasefor variables/functions/parameters/methods,UpperCamelCasefor types/extensions/enums/typedefs,lowercase_with_underscoresfor libraries/packages/file names, leading_for library-private,SCREAMING_CAPSis not idiomatic — uselowerCamelCaseeven for constants. - Formatter / linter:
dart formatis built into the SDK and is the answer (no Prettier-style alternatives).dart analyzeruns the static analyzer; configure viaanalysis_options.yamlwithpackage:lints(the Google-recommended set:core,recommended,flutter) orpackage:very_good_analysis(Very Good Ventures’ stricter preset). Style guide: Effective Dart (https://dart.dev/effective-dart). - Idiomatic patterns: prefer
finalovervar; useconstconstructors aggressively (Flutter optimizes them); use named parameters for clarity (esp. boolean arguments); prefer composition over inheritance; use sealed classes + exhaustiveswitchfor ADTs (3.0+); records for tuples; cascade operator..for fluent setup (obj..a = 1..b = 2). - Expert review focus: missing
conston widget constructors (Flutter perf),setStatefrom outside aStateclass, capturedBuildContextafterawait, growable lists where fixed would do,List<dynamic>from JSON without typing, isolate sends of non-transferable objects, leakingStreamSubscriptions,latefields read pre-init, mirroring in AOT-targeted code.
Ecosystem
- UI frameworks: Flutter (mobile/desktop/web/embedded — the dominant Dart use case), Jaspr (server-rendered web framework with Flutter-like widgets).
- Server-side:
dart_frog(Vercel-style file-based routing, Very Good Ventures),shelf(low-level middleware),serverpod(full BaaS-style backend with codegen client/server),alfred(Express-like). - State management (Flutter): Provider, Riverpod (codegen-driven), BLoC + flutter_bloc, GetX, MobX, Redux.
- DB / persistence: Drift (formerly Moor — type-safe SQLite + Postgres), Isar (NoSQL embedded), Hive, Sembast, ObjectBox, sqflite (raw SQLite).
- Codegen:
build_runner,source_gen,freezed(immutable data classes + unions),json_serializable,injectable,auto_route,retrofit,mockito(build_runner-driven mocking). - Testing:
package:test(the standard runner),flutter_test(widget tests withWidgetTester),integration_test(full-app on-device),mocktail(mockito alternative without codegen),golden_toolkit(Flutter golden image testing),patrol(E2E with native interactions). - Docs:
dart doc(formerlydartdoc) generates HTML from///doc comments. Hosted at https://pub.dev/documentation for every published package. - Notable users: Google (Ads, Pay, Earth, Classroom — many internal apps on Flutter), Alibaba (Xianyu was an early Flutter case study), BMW (My BMW app), eBay Motors, Toyota (in-car infotainment), Tencent (parts of WeChat), ByteDance, Philips Hue, Wonderous (Flutter showcase), Reflectly, Hamilton (the musical’s official app).
Gotchas
intis 64-bit on the VM but JS-numeric (53-bit safe range) on the web. Bigint-style ops fail silently above 2^53 in browsers. UseBigIntfor arbitrary precision.Stringis UTF-16 code units, not Unicode code points. Iterating withfor (var c in str.codeUnits)breaks surrogate pairs; use.runesfor codepoints, orpackage:charactersfor grapheme clusters.==is value equality by default but you must overridehashCodewhenever you override==. The analyzer warns. Usefreezedor records to avoid the boilerplate.asyncfunctions return Future immediately — anything after the firstawaitruns in a microtask, which may alter ordering vs sync code.latefield uninitialized throwsLateInitializationErroronly when read — easy to miss.BuildContextafter async gap (Flutter):if (!mounted) return;after everyawaitin widget code. The analyzer’suse_build_context_synchronouslylint catches this.constconstructors are deeply structural-equal — twoconst Foo(1)literals are the same instance. Lifesaver for Flutter rebuild perf.- Isolate sends copy by default — large objects are expensive. Use
TransferableTypedDataorIsolate.exit(transfers ownership). dart:mirrors+ AOT = doesn’t work. AOT release builds will fail or balloon. Always design around codegen.pubspec.yamlindentation matters — YAML, two spaces.- Flutter SDK pins Dart SDK — using a global
dartoutside Flutter’s bundled one can cause version mismatches. Useflutter pubnotdart pubin Flutter projects, or usefvm. - No method overloading — define optional named parameters or factory constructors instead.
- Equality on
List/Mapis identity, not deep — usepackage:collection’sListEquality/DeepCollectionEquality. - Web targets ship dart2js or dart2wasm output — JS-interop differs from VM
dart:io; conditional imports are mandatory. - Hot reload limits: changing top-level
main, mutating const constructors, or restructuring class hierarchies forces hot restart (state lost).
Citations
- Guides root: https://dart.dev/guides
- Language tour: https://dart.dev/language
- Effective Dart: https://dart.dev/effective-dart
- SDK installation: https://dart.dev/get-dart
- Tools (DevTools, formatter, analyzer): https://dart.dev/tools
- pub package manager: https://dart.dev/tools/pub
- C interop / FFI: https://dart.dev/interop/c-interop
- JS interop: https://dart.dev/interop/js-interop
- Concurrency / isolates: https://dart.dev/language/concurrency
- Async overview: https://dart.dev/language/async
- Sound null safety: https://dart.dev/null-safety
- Records & patterns: https://dart.dev/language/records and https://dart.dev/language/patterns
- Macros (preview): https://dart.dev/language/macros
- VM Service Protocol: https://github.com/dart-lang/sdk/blob/main/runtime/vm/service/service.md
- pub.dev: https://pub.dev/
- DartPad: https://dartpad.dev/
- Flutter docs: https://docs.flutter.dev/
- Version verified 2026-05-06: Dart 3.11 (current stable on dart.dev)