Dart 3.13's Primary Constructors Are a Syntax Rewrite, Not Just Sugar
The new constructor syntax and accompanying lints mark a deliberate, tooling-enforced style shift across the entire Dart and Flutter ecosystem. Teams that ignore it will accumulate technical debt as official docs, packages, and examples converge on the new form, and the `final` parameter pitfall can break existing code on upgrade.
Dart 3.13's Primary Constructors let you declare constructor parameters and instance fields in the class header using `final` and `var`. Parameters without those modifiers remain ordinary constructor parameters and do not become fields, a deliberate design choice that keeps the constructor API explicit. The feature also adds a primary constructor body via `this { ... }` and a new initializer scope, preventing the syntactic cliff where adding a single log line would previously force a rewrite back to the full verbose form.
Alongside this, ordinary constructors can now be declared with `new()` and `factory()` instead of repeating the class name, removing a historical redundancy that complicated future plans for static extension members. The team chose to derive fields from constructor parameters rather than the reverse, arguing that constructor signatures are public API surfaces that need precise control over named/positional parameters, defaults, and const.
Six new lints and IDE assists actively push code toward the new style, signaling that this is not an optional edge syntax but the beginning of a major style migration across the Dart and Flutter ecosystem. Two compatibility pitfalls exist: `final` on function parameters may become a compile-time error, and existing methods named `factory` could be misparsed as factory constructors.
The Dart team explicitly split the long-requested Data Class feature into two separate problems—concise field declaration and value semantics—and solved only the first, leaving `equals`, `hashCode`, and `copy` for later.
Choosing to derive fields from constructor parameters rather than the reverse was a pragmatic call: constructor signatures are public API, and auto-deriving them from fields would create ambiguity around parameter order, optionality, and defaults.
The `const new()` syntax looks jarring but is a logical consequence of decoupling constructor declarations from the class's textual name, a move that also unblocks future language features like constructors in extensions.
The syntactic cliff problem is real and underappreciated; a one-line logic change that forces a 20-line diff discourages incremental refactoring and pushes teams to over-engineer classes early.
Official lint-driven migration means this is not an opt-in experiment—it is a coordinated push toward a new canonical style, similar in weight to the null safety migration.