Dart Versions Evolution (1 to 3+)
Dart Versions Evolution (1 to 3+)
Understanding a language's history isn't just academic — it tells you why certain features exist, why things work the way they do, and where the language is heading.
Dart has gone through three major version milestones, each one transforming it significantly. Let's walk through each era.
📊 Version Overview Table
| Version | Year | Codename/Theme | Biggest Change |
|---|---|---|---|
| Dart 1.0 | October 2013 | Browser Era | First stable release, optional typing |
| Dart 2.0 | August 2018 | Flutter Era | Sound type system, mandatory types |
| Dart 2.12 | March 2021 | Safety Era | Sound Null Safety (NNBD) |
| Dart 3.0 | May 2023 | Expression Era | Records, Patterns, Class modifiers |
| Dart 3.x | 2024–2026 | Platform Era | WASM, Interop improvements |
🗓️ Dart 1.0 (October 2013) — The Browser Era
After two years of development following its announcement in 2011, Dart 1.0 was officially released in October 2013.
What Dart 1.0 Looked Like
Dart 1.0 was designed primarily for structured web development. The goal: give developers a better alternative to JavaScript for large-scale browser applications.
dart// Dart 1.0 era code — Optional typing main() { // Types were OPTIONAL in Dart 1 var greeting = "Hello, Dart 1.0!"; String typed = "I have a type"; // Optional annotation name = "This could be anything!"; // Dynamic — allowed! print(greeting); }
Dart 1.0 Key Features
- ✅ Optional typing —
varor explicit types, developer's choice - ✅ Dartium — special browser to run Dart natively
- ✅ dart2js — compile Dart to JavaScript for other browsers
- ✅ pub — Dart's package manager (pub.dev's predecessor)
- ✅ Libraries — core libraries for math, I/O, collections
- ⚠️ Inconsistent type checking — types were hints, not guarantees
- ❌ No Flutter — Flutter didn't exist yet
The Problem with Dart 1.0
The optional type system sounded flexible, but in practice it created problems:
dart// Dart 1.0 — this was VALID CODE (terrible, but valid) dynamic processUser(user) { return user.name; // What is user? What is name? // Nobody knows until runtime! } // No compile-time error, but crashes at runtime if user has no 'name'
The optional nature of types meant that many Dart 1.0 programs had the same runtime error problems as JavaScript — which defeated the purpose.
[!NOTE] Dart 1.0 had a pub.dartlang.org package repository. By 2015, it had around 3,000 packages. Compare that to pub.dev in 2026 with 40,000+ packages — 13x growth!
Dart 1.0 Ecosystem
Dart 1.0 Stats (2013-2018):
- Packages on pub: ~3,000–15,000
- Dartium: existed but never adopted by other browsers
- Primary use case: Web apps via dart2js compilation
- Flutter: Not yet born (Flutter started as "Sky" in 2015)
🔄 Dart 2.0 (August 2018) — The Flutter Era Begins
Dart 2.0 was the complete reimagination of the language. It is, in many ways, a different language from Dart 1.0 — incompatible in design philosophy if not entirely in syntax.
Released alongside Flutter 1.0 beta, Dart 2.0 marks the beginning of Dart's modern era.
The Core Change: Sound Type System
The biggest change in Dart 2.0 was making the type system sound:
dart// Dart 2.0 — Types are MANDATORY and ENFORCED void main() { // This is Dart 2.0: String name = "Dart 2.0"; int version = 2; // This is now a COMPILE ERROR (was allowed in Dart 1): // String number = 42; // ❌ Error: int can't be assigned to String // Type inference still works (using var) var year = 2018; // inferred as int — cannot reassign to String print("Welcome to $name version $version!"); }
What "Sound" Means
A type system is sound if it can guarantee that typed expressions will never evaluate to a value of the wrong type at runtime:
Dart 1.x (unsound):
String s = someFunction(); // Compiler says "OK", but might crash at runtime
Dart 2.0 (sound):
String s = someFunction(); // If someFunction() doesn't return String,
// it's a COMPILE ERROR — no runtime surprise
This is a huge deal. Sound type systems eliminate entire categories of bugs.
Dart 2.0 Key Features
dart// 1. Mandatory types (or inference) String greet(String name) { return "Hello, $name!"; } // 2. New function syntax — arrow functions String greetShort(String name) => "Hello, $name!"; // 3. Improved class syntax class User { final String name; final int age; // Initializer list constructor User(this.name, this.age); // Named constructor User.anonymous() : name = "Guest", age = 0; String toString() => "User($name, $age)"; } void main() { final user1 = User("Alice", 30); final user2 = User.anonymous(); print(user1); // User(Alice, 30) print(user2); // User(Guest, 0) }
Flutter + Dart 2.0 — The Perfect Marriage
Why Flutter chose Dart 2.0:
AOT Compilation → Native performance (no JS overhead)
JIT Compilation → Hot Reload during development
Sound types → Catch UI errors before running
Async support → Smooth animations, no blocking
No bridge → Flutter talks directly to GPU, no JS bridge
[!IMPORTANT] Dart 2.0 was a breaking change from Dart 1.x. Code written for Dart 1 needed updates. But the community accepted it because the improvements were so significant. This breaking change was the price of building a truly solid foundation.
🛡️ Dart 2.12 (March 2021) — Sound Null Safety
March 2021 brought Dart 2.12 — and with it, what many consider the most important change in Dart's history: Sound Null Safety.
The Billion Dollar Mistake
Tony Hoare, who invented the null reference in 1965, famously called it his "billion dollar mistake" — null pointer exceptions have caused incalculable damage in software history.
Common crash you've seen on Android:
NullPointerException: Attempt to invoke virtual method on null object
Dart 2.12 eliminated this entire category of errors.
How Null Safety Works
dart// BEFORE null safety (Dart 2.11 and earlier): String getUserName() { return null; // Allowed! But crashes callers who expect a String } void printLength(String s) { print(s.length); // 💥 NullPointerException if s is null! } // AFTER null safety (Dart 2.12+): String getUserName() { // return null; // ❌ COMPILE ERROR! String cannot be null return "Dart Developer"; } // To allow null, you MUST use ? suffix: String? getMaybeNull() { return null; // ✅ Allowed — String? means nullable } void printLength(String s) { print(s.length); // ✅ SAFE — s is guaranteed non-null by compiler } void printMaybeLength(String? s) { // Must handle null explicitly: print(s?.length); // null-safe access print(s?.length ?? 0); // default value if null if (s != null) { print(s.length); // smart cast — s promoted to String here } }
Null Safety Operators
dartvoid main() { String? name = null; // ?. (null-aware access) print(name?.toUpperCase()); // null — no crash // ?? (null coalescing — provide default) print(name ?? "Anonymous"); // "Anonymous" // ??= (null-aware assignment) name ??= "Default Name"; // assigns only if name is null print(name); // "Default Name" // ! (null assertion — use carefully!) String definitelyNotNull = name!; // Force unwrap print(definitelyNotNull.length); // Safe only if you're certain // Required named parameters printUser(name: "Alice", age: 30); // type-safe! } void printUser({required String name, required int age}) { print("$name is $age years old"); }
Sound Null Safety = Sound Type System
Dart 2.12 complete soundness:
Non-nullable types: String, int, bool, List, ...
Nullable types: String?, int?, bool?, List?, ...
The compiler tracks nullability everywhere.
If it compiles → it won't throw NullPointerException.
This is what "sound" null safety means.
[!TIP] Null safety might feel restrictive at first — you have to explicitly handle nulls. But within days, you'll realize you're writing more honest, clearer code. Your types document your intent.
🚀 Dart 3.0 (May 2023) — Records, Patterns & Class Modifiers
Dart 3.0 was the most expressive update to the language — it didn't just fix problems, it added powerful new ways to write code.
New Feature 1: Records 📦
Records are lightweight, immutable data structures — perfect for returning multiple values from a function:
dartvoid main() { // Before Records: had to use Map or create a class for multiple returns // After Records: simple and type-safe! var point = (10, 20); // Positional record var person = (name: "Alice", age: 30); // Named record print(point.$1); // 10 — access by position print(point.$2); // 20 print(person.name); // Alice — access by name print(person.age); // 30 // Functions can return multiple values cleanly: var (min, max) = findMinMax([3, 1, 4, 1, 5, 9, 2, 6]); print("Min: $min, Max: $max"); // Min: 1, Max: 9 } (int, int) findMinMax(List<int> numbers) { numbers.sort(); return (numbers.first, numbers.last); // Returns a record! }
New Feature 2: Patterns 🎯
Pattern matching brings powerful destructuring and matching capabilities:
dartvoid main() { // Switch expressions (not just statements) var shape = Circle(radius: 5.0); double area = switch (shape) { Circle(radius: var r) => 3.14159 * r * r, Rectangle(width: var w, height: var h) => w * h, _ => 0.0, }; print("Area: $area"); // Area: 78.53975 // List patterns var list = [1, 2, 3, 4, 5]; var [first, second, ...rest] = list; // Destructuring! print("First: $first, Second: $second, Rest: $rest"); // First: 1, Second: 2, Rest: [3, 4, 5] // Record patterns var (name, age) = ("Alice", 30); print("$name is $age"); // Alice is 30 } sealed class Shape {} class Circle extends Shape { final double radius; Circle({required this.radius}); } class Rectangle extends Shape { final double width, height; Rectangle({required this.width, required this.height}); }
New Feature 3: Class Modifiers 🏗️
Dart 3.0 added fine-grained control over how classes can be used:
dart// base — can be extended but not implemented base class Animal { void breathe() => print("Breathing..."); } // final — cannot be extended or implemented at all final class Singleton { static final Singleton _instance = Singleton._(); Singleton._(); static Singleton get instance => _instance; } // interface — can only be implemented, not extended interface class Drawable { void draw(); // Must implement this } // sealed — exhaustive matching, subclasses in same file only sealed class Result<T> {} class Success<T> extends Result<T> { final T data; Success(this.data); } class Failure<T> extends Result<T> { final String error; Failure(this.error); } void handleResult(Result<String> result) { switch (result) { case Success(:var data): print("Got: $data"); case Failure(:var error): print("Error: $error"); // No default needed — sealed class is exhaustive! } }
Dart 3.0 Requires 100% Null Safety
Dart 3.0 dropped all support for non-null-safe code. If you have old packages without null safety — they won't work with Dart 3.0. The ecosystem had to fully migrate.
[!IMPORTANT] Dart 3.0 is a minimum version for many modern Flutter projects. Make sure you're on Dart 3.0+ to use Records, Patterns, and all modern features.
⚡ Dart 3.x (2024–2026) — The Platform Era
The 3.x series focuses on:
WebAssembly (WASM) Support
Dart 3.x WASM compilation:
Dart Code ──→ WASM Binary ──→ Browser runs at near-native speed
Performance comparison (rough):
JavaScript: 1x
Dart→JS: 1.2x (some overhead)
Dart→WASM: 2-5x (near native!)
Native (C/Rust): 5-10x
Dart Interop Improvements
Better interoperability with JavaScript, C (via FFI), and Java/Kotlin/Swift:
dart// Calling JavaScript from Dart (3.x style) import 'dart:js_interop'; ('Math.random') external double jsRandom(); // Call JS's Math.random from Dart! void main() { double randomValue = jsRandom(); print("JS random: $randomValue"); }
Performance Improvements
- Faster startup times for CLI Dart programs
- Improved garbage collector (shorter pauses)
- Better tree-shaking (smaller compiled output)
- Enhanced Dart DevTools
📦 Dart Ecosystem Stats (2026)
The growth of Dart's ecosystem mirrors the language's evolution:
pub.dev Package Growth:
2013 (Dart 1.0) ▓░░░░░░░░░░░░░ ~3,000 packages
2018 (Dart 2.0) ▓▓▓░░░░░░░░░░░ ~12,000 packages
2021 (Dart 2.12) ▓▓▓▓▓░░░░░░░░░ ~22,000 packages
2023 (Dart 3.0) ▓▓▓▓▓▓▓▓░░░░░░ ~33,000 packages
2026 (Dart 3.x) ▓▓▓▓▓▓▓▓▓▓▓▓░░ ~40,000+ packages
| Metric | 2018 | 2021 | 2023 | 2026 |
|---|---|---|---|---|
| pub.dev packages | ~12K | ~22K | ~33K | ~40K+ |
| Flutter apps (Play Store) | ~10K | ~500K | ~1M+ | ~2M+ |
| GitHub Stars (Flutter) | ~15K | ~130K | ~160K | ~170K+ |
| Dart Survey Satisfaction | 72% | 80% | 85% | 88%+ |
| StackOverflow Ranking | ~30th | ~20th | ~15th | Top 15 |
[!NOTE] Dart consistently scores in the top tier of "most loved languages" in Stack Overflow's annual Developer Survey since 2021.
🔄 Version Compatibility & Migration
Understanding which Dart version your project uses:
yaml# pubspec.yaml — your project's dependency config name: my_dart_project description: A sample Dart project environment: sdk: '>=3.0.0 <4.0.0' # Requires Dart 3.0 or higher! dependencies: http: ^1.2.0 dev_dependencies: test: ^1.24.0
dart// Check which Dart version features you can use: void main() { // Available since Dart 3.0: Records var point = (x: 10, y: 20); print(point.x); // ✅ Dart 3.0+ // Available since Dart 2.12: Null safety String? maybeNull = null; print(maybeNull ?? "default"); // ✅ Dart 2.12+ // Available since Dart 2.0: Sound typing int number = 42; // number = "hello"; // ❌ Dart 2.0 catches this print("Running on Dart ${Platform.version}"); }
🏆 Dart's Biggest Version Milestones — Quick Reference
carousel**Dart 1.0 (2013) — The Beginning** - 🎯 Focus: Structured web development - 🔧 Optional type system - 🌐 Dartium browser (native Dart VM) - 📦 dart2js compiler for other browsers - 👶 Beginner-friendly but not robust at scale - ❌ No Flutter, no null safety, no sound types <!-- slide --> **Dart 2.0 (2018) — The Rebirth** - 🎯 Focus: Flutter + production applications - 🔧 Sound type system (mandatory types) - 🚀 Flutter compatibility era begins - ⚡ AOT + JIT dual compilation - 💥 Breaking change from Dart 1 - ✅ Modern Dart begins here <!-- slide --> **Dart 2.12 (2021) — The Safety Leap** - 🎯 Focus: Eliminating null errors - 🔧 Sound Null Safety (NNBD) - 🛡️ Non-nullable by default - 🎯 Null-aware operators (?., ??, ??=, !) - ✅ Required named parameters - 🏆 Most impactful single release <!-- slide --> **Dart 3.0 (2023) — The Expression** - 🎯 Focus: Developer productivity - 📦 Records (multiple return values) - 🎯 Patterns (destructuring + matching) - 🏗️ Class modifiers (base, final, interface, sealed) - 💯 100% null safety required - ✅ Switch expressions (not just statements) <!-- slide --> **Dart 3.x (2024–2026) — The Platform** - 🎯 Focus: Every platform, maximum performance - 🌐 WebAssembly (WASM) compilation - 🔗 JS/C/Native interop improvements - ⚡ Faster startup, better GC - 📦 40,000+ packages on pub.dev - 🚀 2M+ Flutter apps in production
📝 Summary
| Version | Year | Theme | Learn It For |
|---|---|---|---|
| Dart 1.0 | 2013 | Browser/optional types | Historical context only |
| Dart 2.0 | 2018 | Sound types + Flutter | Foundation of modern Dart |
| Dart 2.12 | 2021 | Null safety | Safety-first programming |
| Dart 3.0 | 2023 | Records + Patterns | Expressive, modern Dart |
| Dart 3.x | 2026 | WASM + Performance | Cutting-edge development |
[!IMPORTANT] This entire course teaches Dart 3.x — the latest and most powerful version. You'll be writing code that takes full advantage of records, patterns, null safety, and all modern features.
[!TIP]
When you see older Dart code online (especially pre-2021), you might notice missing ? for nullable types or different syntax. That's Dart 1.x or early 2.x code. You now know why it looks different!
In the next lesson, we'll set up your Dart development environment — the tools you need to start writing and running Dart code on your machine.