--- title: Dart language evolution shortTitle: Language evolution breadcrumb: Legacy description: Notable changes and additions to the Dart programming language. lastVerified: 2026-08-12 --- :::warning **This page has been deprecated.** See the [Changelog](/changelog) for changes to the language and SDK, and [Language versioning](/language/versioning) for how versioning is used with Dart and the SDK. ::: This page lists notable changes and additions to the Dart programming language. * To learn specific details about the most recent supported language version, check out the [language documentation][] or the [language specification][]. * For a full history of changes to the Dart SDK, see the [SDK changelog][]. * For a full history of breaking changes, including [language versioned][] changes, check out the [Breaking changes][] page. To use a language feature introduced after 2.0, set an [SDK constraint][] no lower than the release when Dart first supported that feature. **For example:** To use null safety, introduced in [2.12][], set `2.12.0` as the lower constraint in the `pubspec.yaml` file. ```yaml environment: sdk: '>=2.12.0 <3.0.0' ``` [2.12]: #dart-2-12 [SDK constraint]: /tools/pub/pubspec#sdk-constraints [language versioned]: /language/versioning [Breaking changes]: /resources/breaking-changes :::tip To review the features being discussed, investigated, and added to the Dart language, check out the [language funnel][] tracker on the Dart language GitHub repo. ::: ## Changes in each release ### Dart 3.13 _Released 12 August 2026_ | [Dart 3.13 announcement](/blog/announcing-dart-3-13) Dart 3.13 introduces [primary constructors][], a concise syntax for declaring a constructor and its instance variables directly in the declaration header: ```dart class Point(var int x, var int y); ``` Primary constructors reduce the boilerplate of declaring fields, passing parameters, and assigning them in a constructor body. They change how you write a declaration, not how it behaves at runtime. Dart 3.13 also adds a [concise constructor syntax][] for constructors declared in the class body: you can write `new` or `factory` instead of repeating the class name. The release also includes the following language-versioned changes to the output of [`dart format`][]: * Adds trailing commas to split extension type representation clauses. * Improves eager splitting to avoid suboptimal line splits. * Prefers splitting call chains with single-element targets. * Allows parameter lists to use block formatting. * Allows `as`, `is`, and `is!` expressions to use block formatting. * Separates imports into distinct sections. * Splits an `if-case` guard when its pattern uses block formatting. * When no formatting solution fits the page width, prefers overflowing lines that end in string literals or comments. * Adds blank lines around `mixin` and `extension type` declarations that don't have a `;` body. For more information about these and additional changes, see the [Dart 3.13 changelog][]. [primary constructors]: /language/primary-constructors [concise constructor syntax]: /language/constructors#concise-constructor-syntax [`dart format`]: /tools/dart-format [Dart 3.13 changelog]: {{site.repo.dart.sdk}}/blob/main/CHANGELOG.md#3130 ### Dart 3.12 _Released 18 May 2026_ | [Dart 3.12 announcement](/blog/announcing-dart-3-12) Dart 3.12 introduces [private named parameters][], which let you initialize private fields directly through [initializing formal parameters][]. Previously, initializing a private field through a named parameter required manual assignment in the constructor's initializer list. Now, when an initializing formal parameter refers to a private field, Dart strips the leading underscore (`_`) to derive the parameter's public name, so callers use the unprefixed name at the call site: ```dart class Point { final int _x; final int _y; Point({required this._x, required this._y}); } void main() { // Callers use the public, unprefixed names of the parameters. final point = Point(x: 1, y: 2); } ``` [initializing formal parameters]: /language/constructors#use-initializing-formal-parameters [private named parameters]: /language/constructors#private-named-parameters ### Dart 3.11 _Released 9 February 2026_ | [Dart 3.11 announcement](/blog/announcing-dart-3-11) While Dart 3.11 introduces no new language features, the release includes several improvements to analyzer and editor support for the [dot shorthand][] syntax introduced in Dart 3.10. [dot shorthand]: /language/dot-shorthands ### Dart 3.10 _Released 12 November 2025_ | [Dart 3.10 announcement](/blog/announcing-dart-3-10) Dart 3.10 introduces [dot shorthands][], a concise syntax that lets you omit explicit type names when accessing enum values, static members, or constructors. If the compiler can infer the type from context, you can now simply use `.foo` instead of the full `ContextType.foo`. ```dart // Use dot shorthand syntax on enums: enum Status { none, running, stopped, paused } Status currentStatus = .running; // Instead of Status.running // Use dot shorthand syntax on a static method: int port = .parse('8080'); // Instead of int.parse('8080') // Uses dot shorthand syntax on a constructor: class Point { final int x, y; Point(this.x, this.y); Point.origin() : x = 0, y = 0; } Point origin = .origin(); // Instead of Point.origin() ``` [dot shorthands]: /language/dot-shorthands ### Dart 3.9 _Released 13 August 2025_ | [Dart 3.9 announcement](/blog/announcing-dart-3-9) The following supporting features have been updated for Dart 3.9: * Null safety: Dart now assumes null safety when computing type promotion, reachability, and definite assignment. As a result of this change, more `dead_code` warnings might be produced. * Flutter upper version bound is now respected: Starting from language version 3.9, the [flutter SDK constraint][] upper bound is now respected in your root package. For example, a `pubspec.yaml` file with the following constraints: ```yaml name: my_app environment: sdk: ^3.9.0 flutter: 3.33.0 ``` Results in `dart pub get` failing if invoked with a version of the Flutter SDK different from `3.33.0`. The upper bound of the `flutter` constraint is still ignored in packages used as dependencies. For more background on this change, see [flutter/flutter#95472][]. For more information about these and additional changes, see the [Dart 3.9 changelog][]. [Dart 3.9 changelog]: {{site.repo.dart.sdk}}/blob/main/CHANGELOG.md#390 [flutter SDK constraint]: /tools/pub/pubspec#flutter-sdk-constraints [flutter/flutter#95472]: https://github.com/flutter/flutter/issues/95472 ### Dart 3.8 _Released 20 May 2025_ | [Dart 3.8 announcement](/blog/announcing-dart-3-8) The following language features have been added to Dart 3.8: * [Null-aware elements][]: A null-aware element evaluates an expression in a collection literal and if the result is not `null`, inserts the value into the surrounding collection. The following supporting features have been updated: * [Dart format][]: Dart 3.8's formatter builds on the previous release's rewrite, incorporating feedback, bug fixes, and further enhancements. It now intelligently automates trailing comma placement, deciding whether to split constructs rather than forcing them. The update also includes style changes to tighten and improve code output. For more information about these and additional changes, see the [Dart 3.8 changelog][]. [Null-aware elements]: /language/collections#null-aware-element [Dart format]: {{site.repo.dart.sdk}}/blob/main/CHANGELOG.md#380 [Dart 3.8 changelog]: {{site.repo.dart.sdk}}/blob/main/CHANGELOG.md#380 ### Dart 3.7 _Released 12 February 2025_ | [Dart 3.7 announcement](/blog/announcing-dart-3-7) Dart 3.7 added support for [wildcard variables][] to the language. A wildcard variable is a local variable or parameter named `_`. Wildcard variables are non-binding, so they can be declared multiple times without collisions. For example: ```dart Foo(_, this._, super._, void _()) {} ``` The `dart format` command is also now tied to the language version as of 3.7. If the language version of an input file is 3.7 or later, the code is formatted with the new tall style. The new style looks similar to the style you get when you add trailing commas to argument lists, except that now the formatter will add and remove those commas for you. When an argument or parameter lists splits, it is formatted like so: ```dart longFunction( longArgument, anotherLongArgument, ); ``` You can find more details in the [changelog][dart-format]. [wildcard variables]: /language/variables#wildcard-variables [dart-format]: {{site.repo.dart.sdk}}/blob/main/CHANGELOG.md#dart-format ### Dart 3.6 _Released 11 December 2024_ | [Dart 3.6 announcement](/blog/announcing-dart-3-6) Dart 3.6 added support for [digit separator][] underscores (`_`) to the language. Digit separators improve readability of long number literals. ```dart var m = 1__000_000__000_000__000_000; ``` [digit separator]: /language/built-in-types#digit-separators ### Dart 3.5 _Released 6 August 2024_ | [Dart 3.5 announcement](/blog/announcing-dart-3-5-and-an-update-on-the-dart-roadmap) Dart 3.5 added no new language features, but made minor changes to the context considered during type inference. These include the following, non-language versioned changes: * When the context for an `await` expression is `dynamic`, the context for the operand of expression is now `FutureOr<_>`. * When the context for an entire if-null expression (`e1 ?? e2`) is `dynamic`, the context for `e2` is now the static type of `e1`. ### Dart 3.4 _Released 14 May 2024_ | [Dart 3.4 announcement](/blog/announcing-dart-3-4) Dart 3.4 made several improvements related to type analysis. These include: * Improvements to the type analysis of conditional expressions, if-null expressions and assignments, and switch expressions. * Aligning the pattern context type schema for cast patterns with the spec. * Making the type schema for the null-aware spread operator (`...?`) nullable for maps and set literals, to match the behavior of list literals. ### Dart 3.3 _Released 15 February 2024_ | [Dart 3.3 announcement](/blog/new-in-dart-3-3-extension-types-javascript-interop-and-more) Dart 3.3 added some enhancements to the language: * [Extension types][] are a new feature in Dart that allow zero-cost wrapping of an existing type. They are similar to wrapper classes and extension methods, but with implementation differences and different tradeoffs. ```dart extension type Meters(int value) { String get label => '${value}m'; Meters operator +(Meters other) => Meters(value + other.value); } void main() { var m = Meters(42); // Has type `Meters`. var m2 = m + m; // OK, type `Meters`. // int i = m; // Compile-time error, wrong type. // m.isEven; // Compile-time error, no such member. assert(identical(m, m.value)); // Succeeds. } ``` * Abstract getters are now promotable under the rules of [private final field promotion][], if there are no conflicting declarations. ### Dart 3.2 _Released 15 November 2023_ | [Dart 3.2 announcement](/blog/announcing-dart-3-2) Dart 3.2 added enhancements to flow analysis, including: * Expanded [type promotion](/null-safety/understanding-null-safety#type-promotion-on-null-checks) to work on private final fields. Previously only available for local variables and parameters, now private final fields can promote to non-nullable types through null checks and `is` tests. For example, the following code is now sound: ```dart class Example { final int? _privateField; Example(this._privateField); void f() { if (_privateField != null) { // _privateField has now been promoted; you can use it without // null checking it. int i = _privateField; // OK } } } // Private field promotions also work from outside of the class: void f(Example x) { if (x._privateField != null) { int i = x._privateField; // OK } } ``` For more information on when private final fields can and can't promote, check out [Fixing type promotion failures](/tools/non-promotion-reasons). * Corrected inconsistencies in type promotion behavior of [if-case](/language/branches#if-case) statements where the value being matched against throws an exception. ### Dart 3.1 _Released 16 August 2023_ | [Dart 3.1 announcement](/blog/dart-3-1-a-retrospective-on-functional-style-programming-in-dart-3) Dart 3.1 added no new features and made no changes to the language. ### Dart 3.0 _Released 10 May 2023_ | [Dart 3.0 announcement](/blog/announcing-dart-3) Dart 3.0 introduced several new major language features: * [Patterns][], a new category of grammar that lets you match and destructure values. * [Records][], a new type that lets you aggregate multiple values of different types in a single function return. * [Class modifiers][], a new set of keywords that let you control how a class or mixin can be used. * [Switch expressions][], a new form of multi-way branching allowed where expressions are expected. * [If-case clauses][], a new conditional construct that matches a value against a pattern and executes the then or else branch, depending on whether the pattern matches. Dart 3.0 also introduced a few breaking language changes: * Class declarations without the [`mixin`][] class modifier can no longer be applied as mixins. * It is now a compile time error if a colon (`:`) is used as the separator before the default value of an optional named parameter. Use an equal sign (`=`) instead. * It is now a compile-time error if a `continue` statement targets a label that is not attached to a loop statement (`for`, `do`, and `while`) or a `switch` member. :::note The 3.0 release of the Dart SDK dropped support for [language versions][] before 2.12. ::: [Patterns]: /language/patterns [Records]: /language/records [Class modifiers]: /language/class-modifiers [Switch expressions]: /language/branches#switch-expressions [If-case clauses]: /language/branches#if-case [`mixin`]: /language/mixins#class-mixin-or-mixin-class [language versions]: /language/versioning ### Dart 2.19 _Released 25 January 2023_ Dart 2.19 introduced some precautions surrounding type inference. These include: * More flow analysis flags for unreachable code cases. * No longer delegate inaccessible private names to `noSuchMethod`. * Top-level type inference throws on cyclic dependencies. Dart 2.19 also introduced support for unnamed libraries. Library directives, used for appending library-level doc comments and annotations, can and [should][] now be written without a name: ```dart /// A really great test library. @TestOn('browser') library; ``` [should]: /effective-dart/style#dont-explicitly-name-libraries ### Dart 2.18 _Released 30 August 2022_ | [Dart 2.18 announcement](/blog/dart-2-18-objective-c-swift-interop) Dart 2.18 enhanced type inference. This change allows information flow between arguments in generic function calls. Before 2.18, if you didn't specify an argument's type in some methods, Dart reported errors. These type errors cited potential null occurrences. With 2.18, the compiler infers the argument type from other values in an invocation. You don't need to specify the argument type inline. Dart 2.18 also discontinued support for mixin classes that don't extend `Object`. To learn more about these features, check out: * [Type argument inference][] * [Adding features to a class: mixins][] [Type argument inference]: /language/type-system#type-argument-inference [Adding features to a class: mixins]: /language/mixins ### Dart 2.17 _Released 11 May 2022_ | [Dart 2.17 announcement](/blog/dart-2-17-productivity-and-integration) Dart 2.17 expanded enum functionality with enhanced enums. Enhanced enums allow enum declarations to define members including fields, constructors, methods, getters, etc. Dart 2.17 added support for super-initializer parameters in constructors. Super parameters allow you to avoid having to manually pass each parameter into the super invocation of a non-redirecting constructor. You can instead use super parameters to forward parameters to a superclass constructor. Dart 2.17 removed some restrictions on named arguments. Named arguments can now be freely interleaved with positional arguments. As of Dart 2.17, you can write the following code: ```dart void main() { test(skip: true, 'A test description', () { // Very long function body here... }); } ``` To learn more about these features, check out: * [Enhanced enums][] * [Super parameters][] * [Named parameters][] [Enhanced enums]: /language/enums#declaring-enhanced-enums [Super parameters]: /language/constructors#super-parameters [Named parameters]: /language/functions#named-parameters ### Dart 2.16 _Released 3 February 2022_ | [Dart 2.16 announcement](/blog/announcing-dart-2-15) Dart 2.16 added no new features to the Dart language. It did expand the Dart tools. ### Dart 2.15 _Released 8 December 2021_ | [Dart 2.15 announcement](/blog/announcing-dart-2-15) Dart 2.15 improved support for function pointers, known as _tear-offs._ In particular, constructor tear-offs are now supported. ### Dart 2.14 _Released 8 September 2021_ | [Dart 2.14 announcement](/blog/announcing-dart-2-14) Dart 2.14 added the unsigned shift (or _triple-shift_) operator (`>>>`). This new operator works like `>>`, except that it always fills the most significant bits with zeros. To learn more about these operators, check out [bitwise and shift operators][]. [bitwise and shift operators]: /language/operators#bitwise-and-shift-operators Dart 2.14 removed some restrictions on type arguments. You can pass type arguments to annotations and use a generic function type as a type argument. As of Dart 2.14, you can write the following code: ```dart @TypeHelper(42, "The meaning") late List(T)> idFunctions; var callback = [(T value) => value]; late S Function(T)>(S) f; ``` ### Dart 2.13 _Released 19 May 2021_ | [Dart 2.13 announcement](/blog/announcing-dart-2-13) Dart 2.13 expanded support for **[type aliases][]** (`typedef`). Type aliases used to work only for function types but now work for any type. You can use the new name created with a type alias anywhere the original type could be used. Dart 2.13 improved the struct support in **[Dart FFI][]**, adding support for inline arrays and packed structs. ### Dart 2.12 _Released 3 March 2021_ | [Dart 2.12 announcement](/blog/announcing-dart-2-12) Dart 2.12 added support for **[sound null safety][]**. When you opt into null safety, types in your code are non-nullable by default, meaning that variables can't contain null unless you say they can. With null safety, your runtime null-dereference errors turn into edit-time analysis errors. In Dart 2.12, **[Dart FFI][]** graduated from beta to the stable channel. ### Dart 2.10 _Released 1 October 2020_ | [Dart 2.10 announcement](/blog/announcing-dart-2-10) Dart 2.10 added no new features to the Dart language. ### Dart 2.9 _Released 5 August 2020_ Dart 2.9 added no new features to the Dart language. ### Dart 2.8 _Released 6 May 2020_ | [Dart 2.8 announcement](/blog/announcing-dart-2-8) Dart 2.8 didn't add any features to the Dart language. It did contain a number of preparatory [breaking changes][2.8 breaking changes] to improve nullability-related usability and performance for [null safety][]. ### Dart 2.7 _Released 11 December 2019_ | [Dart 2.7 announcement](/blog/announcing-dart-2-7-a-safer-more-expressive-dart) Dart 2.7 added support for **[extension methods][]**, enabling you to add functionality to any type —-even types you don't control—- with the brevity and auto-complete experience of regular method calls. The following example extends the `String` class from `dart:core` with a new `parseInt()` method: ```dart extension ParseNumbers on String { int parseInt() { return int.parse(this); } } void main() { int i = '42'.parseInt(); print(i); } ``` ### Dart 2.6 _Released 5 November 2019_ | [Dart 2.6 announcement](/blog/announcing-dart-2-6-with-dart2native-compile-dart-to-self-contained-native-executables) Dart 2.6 introduced a [breaking change (dart-lang/sdk#37985)]({{site.repo.dart.sdk}}/issues/37985). Constraints where `Null` serves as a subtype of `FutureOr` now yield `Null` as the solution for `T`. For example: The following code now prints `Null`. Before Dart 2.6, it printed `dynamic`. The anonymous closure `() {}` returns the `Null` type. ```dart import 'dart:async'; void foo(FutureOr Function() f) { print(T); } main() { foo(() {}); } ``` ### Dart 2.5 _Released 10 September 2019_ | [Dart 2.5 announcement](/blog/announcing-dart-2-5-super-charged-development) Dart 2.5 didn't add any features to the Dart language, but it did add support for [calling native C code][] from Dart code using a new **core library, `dart:ffi`.** ### Dart 2.4 _Released 27 June 2019_ Dart 2.4 introduces a breaking change [dart-lang/sdk#35097]({{site.repo.dart.sdk}}/issues/35097). Dart now enforces covariance of type variables used in super-interfaces. For example: Prior to this release Dart accepted, but now rejects, the following code: ```dart class A {}; class B extends A {}; ``` You can now use `async` as an identifier in asynchronous and generator functions. ### Dart 2.3 _Released 8 May 2019_ | [Dart 2.3 announcement](/blog/announcing-dart-2-3-optimized-for-building-user-interfaces) Dart 2.3 added three operators designed to improve code that performs list manipulation, such as declarative UI code. The **[spread operator][]** enables unpacking the elements from one list into another. In the following example, the list returned by `buildMainElements()` is unpacked into the list being passed to the `children` argument: ```dart Widget build(BuildContext context) { return Column(children: [ Header(), ...buildMainElements(), Footer(), ]); } ``` The **[collection if][]** operator enables adding elements conditionally. The following example adds a `FlatButton` element unless the app displays the last page: ```dart Widget build(BuildContext context) { return Column(children: [ Text(mainText), if (page != pages.last) FlatButton(child: Text('Next')), ]); } ``` The **[collection for][]** operator enables building repeated elements. The following example adds one `HeadingAction` element for each section in `sections`: ```dart Widget build(BuildContext context) { return Column(children: [ Text(mainText), for (var section in sections) HeadingAction(section.heading), ]); } ``` ### Dart 2.2 _Released 26 February 2019_ | [Dart 2.2 announcement](/blog/announcing-dart-2-2-faster-native-code-support-for-set-literals) Dart 2.2 added support for **[set literals][]**: ```dart const Set currencies = {'EUR', 'USD', 'JPY'}; ``` ### Dart 2.1 _Released 15 November 2018_ | [Dart 2.1 announcement](/blog/announcing-dart-2-1-improved-performance-usability) Dart 2.1 added support for **int-to-double conversion**, allowing developers to set `double` values using integer literals. This feature removed the annoyance of being forced to use a `double` literal (for example, `4.0`) when the value was an integer in concept. In the following Flutter code, `horizontal` and `vertical` have type `double`: ```dart padding: const EdgeInsets.symmetric( horizontal: 4, vertical: 8, ) ``` ### Dart 2.0 _Released 22 February 2018_ | [Dart 2.0 announcement](/blog/announcing-dart-2-optimized-for-client-side-development) Dart 2.0 implemented a new **[sound type system][]**. Before Dart 2.0, types weren't fully sound, and Dart relied heavily on runtime type checking. Dart 1.x code had to be migrated to Dart 2. ## Language versioning :::warning Documentation moved This content has been moved to a dedicated page covering Dart [language versioning](/language/versioning). ::: [2.8 breaking changes]: {{site.repo.dart.sdk}}/issues/40686 [calling native C code]: /interop/c-interop [collection for]: /language/collections#control-flow-operators [collection if]: /language/collections#control-flow-operators [Dart library]: /tools/pub/create-packages#organizing-a-package [Dart FFI]: /interop/c-interop [extension methods]: /language/extension-methods [Extension types]: /language/extension-types [language funnel]: {{site.repo.dart.lang}}/projects/1 [language specification]: /resources/language/spec [language documentation]: /language [null safety]: /null-safety [private final field promotion]: /tools/non-promotion-reasons [SDK changelog]: {{site.repo.dart.sdk}}/blob/main/CHANGELOG.md [set literals]: /language/collections#sets [sound null safety]: /null-safety [sound type system]: /language/type-system [spread operator]: /language/collections#spread-operators [type aliases]: /language/typedefs