- Published on
Dart Macros, One and a Half Years After Cancellation — Did the Three Promises Actually Ship?
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- Introduction — The Word That Vanished at I/O 2026
- Timeline — Announcement, Warning Signs, Cancellation
- Why It Died — Semantic Introspection Collided With Hot Reload
- Scorecard 1 — Language Features for Data: Partially Shipped
- Scorecard 2 — build_runner: The Clearest Delivery
- Scorecard 3 — Augmentations: Not Shipped
- The Traces a Dead Feature Left Behind
- So What Should You Do Now
- Closing
- References
Introduction — The Word That Vanished at I/O 2026
The Dart 3.12 announcement, timed to Google I/O in May 2026, never mentions the word "macro" once. Neither does the Dart 3.11 announcement (February 2026), nor the Dart 3.10 announcement (November 2025). That's total silence for a feature that, exactly two years earlier at I/O 2024, was introduced with a large chunk of the release announcement devoted to it, under the banner of "years of investment in the design."
What happened is well known — macros were officially canceled in January 2025. This post isn't a retrospective on that event; it's a post-hoc verification. The cancellation post left three "we'll do this instead" promises, and now, a year and a half later (as of Flutter 3.44.6 + Dart 3.12.2, released July 9, 2026), is a good time to check whether those promises were kept. The verification uses only primary sources, not secondary commentary — the original dart.dev blog posts (the markdown in the site's repository), the Dart SDK and build_runner changelogs, the pub.dev registry API, and GitHub issue status.
Timeline — Announcement, Warning Signs, Cancellation
May 14, 2024, Dart 3.4. The macros preview was unveiled at I/O 2024. The first macro was a single @JsonCodable() that eliminated JSON-serialization boilerplate, and the plan had three stages — a JsonCodable preview → promote the JSON macro to stable if reception was good → eventually open the system so the community could define its own macros. The interesting part is that the post directly names data classes. Data classes are the most-upvoted feature request in the Dart language repository, and the team said that because "opinions differ on what the standard should be," they chose to let the macro system let the community build its own instead of building it into the language. From the start, macros were a proxy solution to the data-class problem.
August 6, 2024, Dart 3.5. Warning signs are already audible in the announcement that doubled as a roadmap update. It says that while most of the language and compiler team's time is going into macros, they're proceeding carefully because macros could regress core use cases like hot reload, and that "it will likely be several more quarters before we can share next steps." Less than three months after the preview shipped, the timeline had already slipped to "several quarters out."
January 29, 2025, cancellation. An update on Dart macros & data serialization goes up under the byline of Dart team member Vijay Menon. Two sentences carry the weight: "each time we solved one major technical hurdle, a new one appeared," and "we will not be shipping macros in the foreseeable future." Eight and a half months passed between the announcement and the cancellation.
Why It Died — Semantic Introspection Collided With Hot Reload
The reason the cancellation post gives isn't performance, and it isn't staffing — it's a collision between the design goals themselves.
The Dart team judged that macros seeing only a program's syntax, the way Rust's procedural macros do, wouldn't be enough to properly solve the goal (problems like data serialization), so they chose deep semantic introspection that queries types and declaration structure at compile time. The problem was the cost of that choice. A macro querying a program's semantic information means that every time code changes, any macro output that depends on that semantics has to be recomputed. In the cancellation post's words, this cost made it "hard to keep stateful hot reload hot," and the implementation at the time was regressing both the editing experience (static analysis, code completion) and incremental compilation (hot reload's first stage).
From a Flutter developer's standpoint, this trade doesn't pencil out. The Dart team itself defines Dart's identity in the cancellation post as two things — AOT performance on par with a static language, and a development cycle (hot reload) on par with a dynamic language. No matter how much boilerplate macros eliminate, if reload gets sluggish on every save, that eats into the core DX asset Flutter holds up against React Native or Compose. Backing off while citing opportunity cost is, on those terms, an understandable call.
Instead, the cancellation post promised three things: (1) "more bespoke language features" for handling data, (2) build_runner improvements, and (3) shipping augmentations — a byproduct prototyped alongside macros — independently. Now let's grade them one by one.
Scorecard 1 — Language Features for Data: Partially Shipped
Small language features did actually land in releases after the cancellation. All of them are confirmed in the SDK changelog and the release announcements.
- null-aware elements — shipped in Dart 3.8 (May 20, 2025). Lets you write an element inside a collection literal that's dropped entirely if it's null.
- dot shorthands — shipped in Dart 3.10 (November 12, 2025). A shorthand syntax that lets you write
.errorinstead ofLogLevel.errorwhen the type can be inferred from context. - private named parameters — shipped in Dart 3.12 (May 20, 2026). Removes the initializer-list boilerplate that used to be forced when initializing a private field via a named parameter.
- primary constructors — released as experimental in Dart 3.12 (requires the
--enable-experiment=primary-constructorsflag). It's already listed as a full language feature in the SDK changelog for the as-yet-unreleased 3.13.
Primary constructors are the main event in this lineage. They fold field declarations and constructor parameters into a single line in the class header.
// Dart until now — five lines for a two-field class
class Point {
final int x;
final int y;
Point(this.x, this.y);
}
// primary constructor — 3.12 experimental, planned for 3.13
class Point(final int x, final int y);
Graded honestly, though, this is "partially shipped." The problem macros originally set out to solve — data classes that automatically generate toJson/fromJson, ==/hashCode/copyWith — is still absent from the language. dart-lang/language#314 (Add data classes) has been open since October 2017 and remains open as of this writing, still one of the top requests with 1,552 upvotes. What's shipped so far is syntax that reduces boilerplate, not something that generates serialization code for you. That job still belongs to the codegen covered below.
Scorecard 2 — build_runner: The Clearest Delivery
Since the alternative to macros ultimately came down to "make build_runner faster," this is the item that matters most. And this one is confirmed by numbers.
Carrying the publication history from the pub.dev registry API over as-is, build_runner before the cancellation was effectively in maintenance mode. From 2.4.0 (January 18, 2023) to 2.4.15 (February 11, 2025), there were 16 releases over 25 months, all patch versions, with not a single minor bump. Things inflect after the cancellation — from 2.5.0 (June 16, 2025) to 2.15.2 (July 13, 2026), 30 releases over 13 months, 11 of them minor-line bumps. The investment the cancellation post promised is stamped right into the registry data.
The content isn't patch-level either. Just in the first half of 2026, per the build_runner changelog:
- 2.13.0 (March 2026) — "a speedup ranging from 1.4x on small initial builds to 4x on large incremental builds." The full benchmark is published in the release PR (dart-lang/build#4405).
- 2.14.0 (April 2026) — "an additional 2x on incremental builds" from improved file management for analysis. Builder compilation switched from JIT to AOT by default (builders using
dart:mirrorsfall back to JIT), and the post explicitly notes the tradeoff: slower initial startup in exchange for faster subsequent builds. - 2.15.0 (April 2026) — removed the
--low-resources-modeflag entirely, citing improved baseline memory usage.
Numbers need a label attached. The 1.4x, 4x, and 2x above are all the Dart team's own benchmark figures. The measurement conditions are the benchmark suite in that release PR, and there's no guarantee your codebase — your combination of builders, package count, workspace layout — will produce the same multiplier. The 4x ceiling comes with the condition "large incremental build" attached. I haven't yet seen an independently reproduced benchmark. That said, the direction itself is consistently pointed to by dozens of changelog entries, and there's no reason to doubt that the improvement exists.
Scorecard 3 — Augmentations: Not Shipped
Augmentations — the feature that lets one declaration be augmented from another file (a foundation for splicing in codegen output more smoothly than part files), which the cancellation post said "has independent value among the features prototyped in macros, and we aim to ship it independently" — hadn't landed in any release as of this writing. The tracking issue dart-lang/language#4154 is still open (last updated February 2026), and there's no augmentation entry in the SDK changelog even through the as-yet-unreleased 3.13 range. Of the three promises, this is the only one where nothing has arrived at all.
For reference, the parent tracking issue for the build_runner improvements (dart-lang/build#3800, "Faster dev cycle") is also still open — meaning delivery is ongoing, not that it's finished.
The Traces a Dead Feature Left Behind
How thorough the cancellation was shows up in how the byproducts were cleaned up. All of this is verifiable right now.
- pub.dev's
macrospackage (stalled at 0.0.1) and thejsonpackage that held JsonCodable (0.20.4, last updated December 2024) both carry a discontinued mark. - The documentation page at dart.dev/language/macros now 301-redirects to the cancellation blog post. It's an unusual sight — a feature-documentation URL leading straight to that feature's obituary.
Meanwhile, the things macros were meant to replace are alive and well. Per pub.dev, json_serializable is still releasing, at 6.14.0 (May 15, 2026), and freezed at 3.2.5 (February 3, 2026). Dart data serialization in 2026 is still codegen — what's changed is that the engine running that codegen got faster.
So What Should You Do Now
If you've been postponing a decision while waiting for macros, close it out. The official position is "not in the foreseeable future," and macros aren't even mentioned in the last three release announcements (3.10, 3.11, 3.12). A long-term metaprogramming exploration issue (#1482) is open, but nothing is on the roadmap.
Upgrading build_runner to the latest is a cheap win. If your project is still stuck on 2.4.x, there are multiple layers of performance improvements stacked up on the way to 2.15.x. Just be aware before you upgrade that first startup can get slower since AOT compilation became the default from 2.14.0 on, and that a builder depending on dart:mirrors will fall back to JIT.
Don't turn primary constructors on yet. In 3.12 it's still behind an experimental flag, and experimental features can change syntax between releases. It's true that it's formally listed in the 3.13 changelog, but 3.13 hasn't been released yet — an unreleased changelog is a plan, not a promise.
There's no reason to rip out your freezed/json_serializable stack. Until the day the language builds in data classes (#314 has been open since 2017), codegen is Dart's data story, full stop. Where this stack sits within the broader Flutter ecosystem is covered as-is in React Native vs Flutter 2025: The Complete Cross-Platform Mobile Development Guide.
Closing
Feature cancellations usually happen quietly — an issue sits neglected for years and then gets closed, documentation quietly disappears. The Dart macros cancellation is worth reviewing precisely because it was the opposite — it explained the reason (semantic introspection's compile-time cost being incompatible with hot reload) technically, named three alternatives explicitly, and one and a half years later, two of those three are shipping in a form verifiable through release and registry data.
At the same time, the scorecard is incomplete. Augmentations hasn't arrived, data classes remain the top-ranked request on the issue tracker, and build_runner's speed numbers are still team-measured only. If there's a lesson left behind by the death of macros, it's probably this — hot reload is an inviolable asset Dart won't trade for any language feature, and under that constraint, Dart's metaprogramming will, for the time being, stay at the answer of "faster codegen."
References
- An update on Dart macros & data serialization — the original cancellation notice (2025-01-29)
- Announcing Dart 3.4 — the macros preview announcement (2024-05-14)
- Announcing Dart 3.5, and an update on the Dart roadmap (2024-08-06)
- Announcing Dart 3.10 — dot shorthands, build hooks (2025-11-12)
- Announcing Dart 3.11 (2026-02-11)
- Announcing Dart 3.12 — private named parameters, primary constructors experimental (2026-05-20)
- Dart SDK CHANGELOG — entries for 3.12.0 and the unreleased 3.13.0
- build_runner CHANGELOG — performance entries for 2.13.0/2.14.0/2.15.0
- dart-lang/language#314 — Add data classes (open)
- dart-lang/language#4154 — Augmentations (open)
- dart-lang/build#3800 — Faster dev cycle (open)
- Flutter SDK release archive JSON — for confirming 3.44.6/Dart 3.12.2