Skip to content
Dart logo

Dart

First appeared 2011 · Lars Bak

Google's language for Flutter — one codebase compiled to native mobile, desktop and web.

Overview

Dart is a client-optimised programming language developed by Google for building fast applications across mobile, web, desktop and server from a single codebase. It is statically typed with sound null safety, and compiles ahead-of-time to native machine code for production and just-in-time during development, which is what enables Flutter's sub-second hot reload. Dart's syntax is deliberately familiar to anyone coming from Java, C# or JavaScript, which lowers the cost of adopting it. The language is almost always encountered through Flutter, Google's UI toolkit, where Dart's compilation model and predictable performance characteristics matter more than they would in isolation. Beyond Flutter, Dart compiles to efficient JavaScript for the web and to standalone native executables for command-line tools and servers, giving one language a genuinely wide deployment range.

Key facts

The reference details, without the paragraph.

First appeared
2011
Designed by
Lars Bak and Kasper Lund at Google
Typing
Static and sound, with full null safety since Dart 2.12
Execution
JIT during development for hot reload, AOT to native machine code for release
Memory model
Automatic — generational garbage collection tuned for short-lived UI objects
Package manager
pub, backed by pub.dev
File extensions
.dart
Current version
Dart 3.x, released alongside each Flutter version
Compile targets
ARM and x64 native, JavaScript, WebAssembly
Licence
BSD 3-clause

History

How the language got here — the decisions that still shape how you write it.

Dart was announced by Google in 2011 with the ambitious and ultimately abandoned goal of replacing JavaScript in the browser — Chrome was to ship a native Dart VM. That plan was dropped in 2015 when it became clear the web would not accept a second scripting language, and Dart pivoted to compiling to JavaScript instead. The language's real breakthrough came with Flutter, announced in 2017. Flutter needed a language that could be interpreted quickly during development for hot reload and compiled to fast native code for release, with predictable performance and no dependency on platform UI widgets. Dart, controlled entirely by Google and designed by Lars Bak — who had previously built the V8 JavaScript engine and the HotSpot JVM — fitted precisely. Dart 2 in 2018 made the type system sound, and Dart 3 in 2023 added pattern matching, records and sealed classes, bringing it closer to modern typed languages. Today Dart's fortunes are essentially tied to Flutter's, and Flutter has become one of the most widely used cross-platform UI frameworks in the industry.

  1. 2011

    Announced as a JavaScript replacement

    Google unveils Dart with the stated goal of shipping a native Dart VM in Chrome. The web ecosystem does not take to the idea of a second scripting language.

  2. 2015

    The browser VM is abandoned

    Google drops the plan to embed Dart in Chrome and commits to compiling to JavaScript instead. For a period the language looks like it may not find a purpose.

  3. 2017

    Flutter changes everything

    Flutter is announced and Dart becomes its language. The pairing works because Dart supports both fast JIT for hot reload and AOT compilation for release performance — few languages do both well.

  4. 2018

    Dart 2 makes the type system sound

    Optional typing is removed in favour of a sound static type system, so a variable's declared type is guaranteed at runtime.

  5. 2021

    Sound null safety

    Nullable and non-nullable types become distinct, eliminating null dereference errors at compile time rather than runtime.

  6. 2023

    Dart 3 — records, patterns and sealed classes

    Pattern matching, destructuring, records and sealed class hierarchies bring Dart in line with modern typed languages, and make exhaustive state handling checkable.

  7. 2024–2025

    WebAssembly and continued Flutter growth

    Dart gains a WebAssembly compilation target, improving web performance substantially, while Flutter consolidates its position in cross-platform development.

What it is good at

The reasons teams pick it, stated concretely.

  • Hot reload genuinely changes the feedback loop

    Sub-second reload with state preserved means you adjust a widget and see the result before you have looked away. This is the single feature Flutter developers cite most, and it depends on Dart's JIT.

  • Sound null safety, not best-effort

    The compiler guarantees a non-nullable variable is never null, including across generics and collections. Unlike gradual approaches, there is no unchecked corner where null slips through.

  • One codebase, six targets

    iOS, Android, web, Windows, macOS and Linux from the same source, with genuinely native compiled output rather than a web view. For a small team this is a large multiplier.

  • Deliberately unremarkable syntax

    Anyone from Java, C#, Swift, Kotlin or TypeScript can read Dart within an hour. That was a design goal, and it makes team adoption far cheaper than a more novel language would be.

  • Predictable performance for UI

    AOT compilation with a garbage collector tuned for many short-lived objects suits the allocation pattern of a widget tree being rebuilt sixty times per second.

Trade-offs

Every language costs you something. Knowing what, before you commit, is the whole point.

  • Effectively tied to Flutter

    Almost nobody chooses Dart for its own sake. Server-side Dart works and the tooling is good, but the ecosystem, jobs and community are all downstream of Flutter's popularity.

  • A smaller package ecosystem

    pub.dev is healthy but far smaller than npm, PyPI or Maven Central. For a niche need you are more likely to write it yourself or wrap a platform API.

  • Deeply nested widget code

    Flutter's composition model produces heavily indented build methods. Dart 3's improvements help, but reading an unfamiliar screen still often means tracing eight levels of constructor arguments.

  • Platform integration still needs platform code

    Anything beyond what a plugin already exposes means writing Swift or Kotlin behind a platform channel — so cross-platform does not mean you can avoid knowing the platforms.

  • Web output is heavy

    A Flutter web build ships a rendering engine, so initial download and time to first paint are poor compared with a conventional web application. WebAssembly improves it but does not close the gap.

Code examples

Not syntax tours — the idioms that make code read like the language rather than a translation of another one.

Null safety in the type system
class User {
  final String name;        // can never be null
  final String? email;      // explicitly may be null

  const User({required this.name, this.email});
}

String describe(User? user) {
  // The compiler refuses `user.name` until you handle the null case.
  if (user == null) return 'anonymous';

  // After the check, `user` is promoted to non-nullable.
  final contact = user.email;
  if (contact != null && contact.contains('@')) {
    return '${user.name} <$contact>';
  }
  return user.name;
}

// The ?? operator supplies a fallback; ?. short-circuits on null.
final label = user?.email ?? 'no email';
Type promotion is the detail that makes this pleasant: after `if (user == null) return`, the compiler treats `user` as non-nullable for the rest of the function, so no repeated unwrapping is needed.
Records and pattern matching
// A record — a lightweight tuple with named fields, no class needed.
(String, int) parseVersion(String raw) {
  final parts = raw.split('.');
  return (parts[0], int.parse(parts[1]));
}

final (major, minor) = parseVersion('3.5');   // destructured

sealed class Result<T> {}
class Success<T> extends Result<T> { final T value; Success(this.value); }
class Failure<T> extends Result<T> { final String message; Failure(this.message); }

String render(Result<List<String>> result) => switch (result) {
  Success(value: final items) when items.isEmpty => 'nothing found',
  Success(value: final items) => '${items.length} items',
  Failure(message: final m) => 'error: $m',
};
Because `Result` is sealed, the compiler knows every subclass and the switch needs no default. Add a third case and every incomplete switch becomes an error.
Async, futures and streams
Future<Dashboard> loadDashboard(String userId) async {
  // Both requests start immediately and run concurrently.
  final results = await Future.wait([
    api.fetchProfile(userId),
    api.fetchOrders(userId),
  ]);

  return Dashboard(results[0] as Profile, results[1] as List<Order>);
}

// Streams model a sequence of asynchronous values.
Stream<int> countdown(int from) async* {
  for (var i = from; i > 0; i--) {
    await Future.delayed(const Duration(seconds: 1));
    yield i;                       // emits without ending the stream
  }
}

await for (final tick in countdown(3)) {
  print(tick);
}
Awaiting each request in sequence would double the wait for no reason. `Future.wait` is the idiomatic fix, and `async*` with `yield` is how you produce a stream rather than a single value.
A Flutter widget with state
class BookList extends StatelessWidget {
  final List<Book> books;
  final void Function(Book) onSelect;

  const BookList({super.key, required this.books, required this.onSelect});

  @override
  Widget build(BuildContext context) {
    // ListView.builder only builds the rows currently on screen.
    return ListView.builder(
      itemCount: books.length,
      itemBuilder: (context, index) {
        final book = books[index];
        return ListTile(
          key: ValueKey(book.id),
          title: Text(book.title),
          subtitle: Text(book.author),
          onTap: () => onSelect(book),
        );
      },
    );
  }
}
`ListView.builder` rather than `ListView(children: [...])` is the difference between building ten visible rows and building ten thousand. The `const` constructor lets Flutter skip rebuilding this widget when its inputs have not changed.

Common pitfalls

The mistakes that cost everyone an afternoon at least once.

  • Calling setState for everything

    Rebuilding a whole screen to update one label is the most common Flutter performance problem. Push state as far down the tree as possible, or use a state management library with granular rebuilds.

  • Missing const constructors

    A `const` widget is not rebuilt when its parent rebuilds. Omitting it means Flutter reconstructs subtrees unnecessarily — enable the `prefer_const_constructors` lint.

  • Using BuildContext after an await

    The widget may have been disposed while the future was in flight. Guard with `if (!context.mounted) return;` before touching context after any await.

  • Building lists eagerly

    `ListView(children: [...])` constructs every child immediately. Use `ListView.builder` for anything longer than a screenful.

  • Not disposing controllers

    AnimationController, TextEditingController, StreamSubscription and ScrollController all need disposing in `dispose()`, or they leak and keep firing.

  • Reaching for `late` to silence null errors

    `late` defers the null check to runtime, converting a compile error into a LateInitializationError. Use it only when initialisation genuinely cannot happen at construction.

In production

Where it is running at scale, and what it is doing there.

  • Google

    Google Pay, Google Ads and Google Classroom are built with Flutter and Dart.

  • BMW

    The My BMW app, shipped to iOS and Android from one Flutter codebase.

  • Alibaba

    Xianyu, its second-hand marketplace, uses Flutter for a shared mobile interface.

  • Nubank

    Migrated its mobile banking apps to Flutter to unify iOS and Android development.

Learning path

A realistic order to learn things in, with something to build at each step.

  1. 1

    Week 1

    The language on its own

    Variables and `final`, functions with named and optional parameters, classes and constructors, collections, and null safety. Use DartPad in the browser — no installation needed.

    Build this: Write a command-line program that reads a JSON file and prints a summary.

  2. 2

    Week 2

    Asynchrony

    Futures, `async`/`await`, `Future.wait`, streams and `async*`. Flutter is asynchronous throughout, so this is not optional background knowledge.

    Build this: Fetch from a public API, handle errors and loading, and print results as they arrive.

  3. 3

    Weeks 3–5

    Flutter fundamentals

    Widgets, the difference between stateless and stateful, layout with Row, Column and Flex, navigation, and `ListView.builder`. Learn why `const` constructors matter for rebuild performance.

    Build this: Build a two-screen app that lists items from an API and shows a detail view.

  4. 4

    Weeks 6–8

    State management and persistence

    Pick one approach — Riverpod, Bloc or Provider — and learn it properly rather than sampling all three. Add local storage, and structure the app into layers.

    Build this: Add offline caching and a settings screen that persists across restarts.

  5. 5

    Ongoing

    Shipping and platform depth

    Platform channels for native APIs, Flutter DevTools for profiling rebuilds and jank, testing at widget and integration level, and the release process for each store.

    Build this: Profile a janky screen in DevTools and fix the unnecessary rebuilds causing it.

Ecosystem and tooling

The tools you will end up installing whichever project you join.

ToolWhat it does
FlutterThe UI toolkit that is the reason to use Dart — mobile, desktop and web from one codebase
pub / pub.devPackage manager and registry, built into the Dart SDK
Riverpod / BlocThe two dominant state management approaches; Provider is the simpler legacy option
DioHTTP client with interceptors, retries and request cancellation
freezed + json_serializableCode generation for immutable data classes and JSON mapping
Flutter DevToolsWidget inspector, rebuild profiler, memory and network views
Drift / IsarLocal persistence — Drift is SQLite with typed queries, Isar is a NoSQL alternative
very_good_analysisA strict lint rule set, considerably stricter than the defaults

Dart libraries

Library coverage for Dart is on the way.

The guide above is complete. In the meantime, the catalogues for Python, Java, JavaScript, C and C++ are fully written.

Browse all libraries

Frequently asked

Is it worth learning Dart if I am not going to use Flutter?

Honestly, rarely. Dart is a perfectly good general-purpose language with excellent tooling, and server-side Dart works, but its ecosystem, community and job market are overwhelmingly Flutter-driven. Learn it because you want to build cross-platform apps, not on general merit.

Flutter or React Native?

Flutter renders its own widgets with Skia or Impeller, so the UI is pixel-identical across platforms and performance is more predictable — at the cost of not using native controls. React Native uses actual platform components and lets you reuse React knowledge and the npm ecosystem. Flutter usually wins on consistency and animation smoothness; React Native wins if your team already writes React.

Which state management should I use?

Riverpod for new projects — it is compile-time safe, testable and does not depend on BuildContext. Bloc if your team wants strict, event-driven structure and an audit trail of state changes. Provider is simpler and still perfectly serviceable for small apps. Pick one and learn it properly; the common failure is sampling all three.

Is Flutter web production-ready?

It works, but it ships a rendering engine to the browser, so the initial download and time to first paint are poor compared with a normal web app, and text selection, SEO and accessibility are weaker. It suits internal tools and app-like experiences. For a public marketing site or anything SEO-dependent, use a conventional web stack.

What does sound null safety actually mean?

That the compiler can prove a non-nullable variable is never null, so it can remove null checks from the generated code entirely. This is stronger than TypeScript's or Kotlin's approach, where unchecked code at a boundary can still introduce a null the type system believed impossible.

How large is the Dart job market?

Smaller than JavaScript, Python or Java, but growing steadily and almost entirely advertised as Flutter roles rather than Dart roles. It is a strong niche — particularly for agencies and startups shipping to both mobile platforms with a small team.