Repository navigation
Open
Labels
area-metaCross-cutting, high-level issues (for tracking many other implementation issues, ...).Cross-cutting, high-level issues (for tracking many other implementation issues, ...).
Description
The Dart core library dart:mirrors is being formally deprecated starting in the November 2026 stable release (Dart 3.14), with complete removal planned for Dart 4.0.
Status
dart:mirrors has long been documented as experimental and unstable:
- Marked "experimental" in the core library documentation.
- Unsupported on the Dart Web platform (dart2js, DDC).
- Unsupported on Dart WebAssembly (dart2wasm).
- Disabled in the Flutter framework (flutter/flutter#1150).
As of Dart SDK commit 541360, dart:mirrors has been annotated with @deprecated on main.
Rationale
Making dart:mirrors a stable, supported core library across all targets is fundamentally incompatible with the architecture and goals of modern Dart:
- AOT Compilation & Tree Shaking: Dart relies heavily on global static whole-program analysis and dead code elimination to produce small, fast binaries. Full runtime reflection requires retaining arbitrary metadata and executable code that could theoretically be reached dynamically, preventing effective tree shaking.
- Platform Portability: Dart's commitment is cross-platform portability across native architectures (AOT/JIT), Web (JavaScript), and WebAssembly (Wasm). A reflection mechanism that cannot be ported to Web, Wasm, or Flutter fractures the ecosystem and limits code sharing.
- Language Evolution Drift: The
dart:mirrorsAPI was designed during Dart 1. It does not model modern Dart features (sound null safety, extension methods, extension types, records, pattern matching), and maintaining parity with ongoing language features would require significant runtime overhead and compiler complexity.
Timeline & Next Steps
- November 2026 Stable Release (Dart 3.14):
dart:mirrorsis marked@deprecated. Compiling code that importsdart:mirrorswill emit deprecation warnings, but code will continue to execute on the standalone Dart VM. - Dart 4.0:
dart:mirrorswill be removed entirely from the Dart SDK.
Recommended Alternatives & Migration
In auditing remaining dart:mirrors usages across the ecosystem, most call sites do not require full runtime reflection and can migrate to simpler standard library or static analysis APIs:
- Resolving Package or Script Paths: Replace
currentMirrorSystem().findLibrary(...)orClosureMirror.function.locationfile lookups withIsolate.resolvePackageUriSync(Uri.parse('package:foo/foo.dart'))(dart:isolate) orPlatform.script(dart:io). - Static Code Inspection (Tests & Tooling): Replace
reflectClass/LibraryMirrordeclaration checks in tests and linters withpackage:analyzer(parseStringfrompackage:analyzer/dart/analysis/utilities.dartfor fast single-file AST inspection, orAnalysisContextCollectionwhen resolved element types are needed). - Enums, Dispatch & Test Runners: Replace reflective enum iteration and string-based method dispatch (
InstanceMirror.invoke) with built-inEnum.values/.byName(), exhaustiveswitchexpressions, and standardpackage:testgroup()/test()blocks. - Code Generation: Use
package:build,package:build_runner, andpackage:source_gen(orjson_serializable,built_value,freezed) for serialization, dependency injection, and boilerplate generation. - Ahead-of-Time Reflection: For workloads requiring reflection-like runtime capabilities, use pre-generated reflection via
package:reflectableandpackage:reflectable_builder.
Reacted by Jonathan Rezende, Aloïs Deniel, Jacob Bang, Hillel Coren, Kevin Segaud, Kevin Moore, Matan Lurey, Oliver Sand, Warren Strange, Sigurd Meldgaard and 25 more
Reacted by Zalán Meggyesi, gothamgasworks, Konstantin Scheglov, Natalie Weizenbaum, BLeAm, Bob Jackman, Peter MATO, Silentdoer, Jonas Sander, Max and 14 more
Reacted by Daniel Varga-Hali, Xavier H., Zalán Meggyesi, gothamgasworks, Silentdoer, inkalsee2, Pouya Kary ✨, Ricardo Romero, Efra Espada, Mohammed Anish and 1 more
Reacted by Dominik Roszkowski, Denis Anokhin, Islam Akhrarov and Ricardo Romero
Metadata
Metadata
Assignees
Labels
area-metaCross-cutting, high-level issues (for tracking many other implementation issues, ...).Cross-cutting, high-level issues (for tracking many other implementation issues, ...).
Activity
daniel-v commentedon Dec 16, 2020
To make sure the info gets to you, here is my response to dart-misc mailing list:
I might be reading too much into this but discontinuing
dart:mirrorslibrary has some serious consequences that were not mentioned in your mail. The most important is that we'd lose the ability to do runtime reflection at our server-side code. It is an HTTP server that uses mirrors for the most important bits of it. Transitioning away from it is a scary proposal for many reasons.If anything I'd request to add mirrors to AOT snapshots too, instead of discontinuing, so that we'd get to deploy our code as a single binary with all the benefits and drawbacks it means. But... Let me address the concerns I have:
I'm sure you have a list of pros and cons for mirrors vs. code generation too. Having said that, I'm not against the idea completely if there are good enough reasons.
I'd have to bite my lips hard if mirrors were removed today and would have to migrate to pacakge:build but luckily we still have some time.
There have been several precedents where such a change was preceded by preparing users, crafting new tools or giving some extra attention to alternatives. Most recent one is the NNBD tooling to this. I hope it is the case here as well, in which case feedback on why I'm nervous about moving to
pacakge:buildis warranted here. In my opinion, build and associated packages are in a bad spot right now.My recent incursions to writing builders were ... trying because:
build.yamlandbuild.config.yamlare merged together instead of being taken as an absolute configuration BUT with a huge caveat: builder declarations are ignored frombuild.config.yaml.What is the first method in this class with an annotation of Route('/')?Example of how complicated it can be just to resolve types here (used by Angular Compiler too).I've had some steep learning curves over the years.
package:buildwas one of them. The primary reason - which I consider the most important of all - is a conceptual one: Code generation is becoming more and more important piece of the language ecosystem. As such, as a user of the language, my expectation is that such an important piece is well-documented, somewhat fool proof and fairly easily approachable.I hope that this is the kind of feedback you were looking for to help you make the right decisions.
mit-mit commentedon Dec 16, 2020
To those downvoting, it would be great if you could also post a comment with what concerns you. As mentioned, we'd like to understand the use cases where you use mirrors today, so that we can investigate if there is an alternate way by which we can support those use cases without mirrors.
zmeggyesi commentedon Dec 16, 2020
I work with @daniel-v and @gothamgasworks - I can second Daniel's input that removing runtime reflection would impact us quite negatively.
Our product actively uses runtime reflection in server-side Dart code, both in production and in development, and our preference would be to retain the ability to introspect code rather than rely on build-time code generation, both in the interest of development cycle times and ease of understanding of deployed code.
gothamgasworks commentedon Dec 16, 2020
@daniel-v 's summary is pretty good, I agree with them.
Some things I want to emphasize:
gothamgasworks commentedon Dec 16, 2020
We use dart:mirrors in:
Of course we could work around it with builders, I would just like to be able to not work with the builder/analyzer API, which requires a serious amount of maintenance as opposed to the mirrors API.
isoos commentedon Dec 16, 2020
The use cases I had in the past month:
abstract class Api { Future<Rs> operation(Rq rq); ...}like API definition and binding it to both.My wish-list, which would probably make the lack of
dart:mirrorsbearable:Fast and simple-to-use source code parser library and good AST/API to extract the annotations, classes and methods that are of the interest of the tool (without specifying upfront which parts we are interested in). My problem with
package:source_genand related build-utilities is their complexity: they are two levels up the chain, they use the framework approach (having a single but somewhat complex way to do things), as opposed to a library that exposes the data and allows the tool to process it as they want.package:analyzeris not really without ceremonies either, but at least it is "only" a library. Sometimes I don't even need to explore the types recursively, I just need the field/methods's name the parameter names and their types. It is not an issue if the full source graph is not available right away, in many cases it may be a (performance) benefit.A separate source code generator, that is not tied to any convention (e.g. not every project wants to use
partfor the generated files, nor do they necessarily want to place only a single file in the same directory as the source). I have done at least 4 separate code generators in the past years, and they had different requirements about these, and it was just easier to do String concatenation + custom file placement + callingdartfmtthan to use any of the big frameworks. I want to build my source code in a programmatic way, the library can enforce the structure (class, method, function boundaries) and format it nicely, and that's all it needs to do. E.g.source_genexamples are full of generators, which assume that I want only to plug in a small piece somewhere. Instead, it should just take the tree as I build it.A trigger mechanism which detects when the generator chain needs to run. I think the situation here is rather good, and I don't have much preference:
package:build_runner's approach may be okay (if made simple for generic tool use), or evenpackage:watchercan be used if the programmatic approach is preferred by the developer.A more convenient way to live-reload classes in the Dart (JIT) VM.
package:vm_service+package:watchershould be really a VM flag that can trigger a reload of classes locally, without further configuration or without adding dependencies to the application under development. (Yes, it may not cover 0.1% of the changes that may happen, e.g. depending on a new package, but restarting the local dev app every once in a while is not an issue. Restarting it every time is.)Summary: To replace
dart:mirrors, the following tools need to be available:scheglov commentedon Dec 16, 2020
The Dart Analyzer team uses
package:test_reflective_loaderextensively for all our tests, and it is based on using mirrors. We found out early that vanillapackage:testis not structured enough for complicatedpackage:analyzertests.lexaknyazev commentedon Dec 16, 2020
My use case of reflection is docs generation via iterating over class members and invoking them to get sample outputs. The code using
dart:mirrorsresides in agrindertask thus being completely unaffected by the lack of support by web and AOT runtimes.jakemac53 commentedon Dec 16, 2020
I have mentioned this elsewhere but worth mentioning here for posterity - build_runner uses dart:mirrors in order to discover all of the libraries that exist in a program. In our case that is the build script itself, and we use that to know if we need to invalidate the snapshot.
gmpassos commentedon Dec 16, 2020
I think that a new framework for reflection should exists. For now we should kill dart:mirrors.
In the future, after NNBD, a new framework should exists with another name. One where you can mark classes that should have their full description after compilation (the main information needed for runtime reflection). The marked classes could be by annotation or passing a list of classes for the "refletor factory" that should be tracked, allowing any class to be tracked for reflection. With that approach,Dart tree shaking won't be affected, unless you really need a reflected class for your project.
nex3 commentedon Dec 16, 2020
dart:mirrorsis used by Grinder, which is the best (and only) task runner for Dart with an 84% popularity rating on pub.dev, and my themustachepackage which is used by both Dartdoc and the 99%-popularitygoogle_fontspackage. Both of these are load-bearing ecosystem packages. Removingdart:mirrorswithout a clear plan for something similarly usable for these packages would cause a lot of downstream pain and chaos.It's worth noting that @isoos's proposed solution would likely not be sufficient for Grinder, since it's infeasible to have a code generation step as part of a task runner workflow.
tvolkert commentedon Dec 17, 2020
This (a) doesn't solve all the problems with dart:mirrors, and (b) would only cater to specific use cases, but leaving the idea here nonetheless... what if we were to still tree-shake as normal even in the presence of dart:mirrors, and rely on developers marking methods as
@pragma("vm:entry-point")?DavidLiedle commentedon Dec 17, 2020
My use case is... well, hold on just a dang minute.
I don't think I should have to lay out my thinking process to express the fact that I value the presence of
dart:mirrorsin the language. This "what is your use case?" approach smells of management and budgeting issues; not of nurturing the Dart ecosystem with an optimistic eye on the 10-20 year future of the language.So allocate the dev resources to get on that. "Significantly behind" is a prioritization issue.
This is plainly technical debt. Defenestrating a sub-section of your server-side users building ORMs (oops, there's my use case..) would be an easy way out, and clearly a cheaper path forward. But seriously, cheaper over better? Not very Googley, imho. Do the right thing. Strive for excellence (and make the one thing you're doing really well be creating a language that can be used everywhere, including places where reflection makes sense). Keep an eye on the goals (both short and long term). Be proactive (and bring dart:mirrors up to par). Go the extra mile... Well, you know all this. You're the ones that work there.
I've been one of the earliest, most enthusiastic, and staunchest allies of both Dart and Flutter, but the bloom is off the rose with several prioritization choices that make me just, well, nervous. I'm tired of building things in AngularDart, or Polymer.dart (oy..), and then getting downstream just enough to feel the aging, unfinished edges and have to admit to myself that it's not a viable path forward. I have had to abandon chunks of my work because of hitting these dead ends and faded photos of what was planned. It's turning my attention to other places, and mine has teh sad. It took this thread for me to even glance back at AngularDart and see that it received an update in October of this year. Yay! But.. I can't trust it; already tried that, and got left behind.
TL;DR: this decision will impact the trust of your user base regarding your team's intentions in general; trust that is already flying on one engine. If we smell even a whiff of "Flutter doesn't need it so it's getting de-funded", even the features you do nurture will be untrusted for any other use case, and weaken your entire value proposition. Many of us, even your biggest fans, will simply walk. Not a rage-quit, but a pragmatic step out of what would appear to be a populism-driven-dev world and into other environments that focus on remaining well-rounded. Over time. For everyone.
The End
zmeggyesi commentedon Dec 17, 2020
@gmpassos
Not without a replacement being widely available and adopted we shouldn't!
Evidently,
mirrorsand reflection as a whole is widely used, in load-bearing packages as @nex3 points out, not to mention in the major task runner of the ecosystem. Killingmirrorswithout a replacement at this point pretty much breaks the ecosystem; killing it with a replacement that's not (near-)universally adopted does the same.If the team moves forward with deprecating and removing this, it should only be done after they provided a replacement framework/solution, and the majority of the ecosystem, or at least its core components, have transitioned to the new way of doing things.
79 remaining items
francescovallone commentedon Feb 23, 2024
Good afternoon 👋!
Sorry to bother, but I'm trying to understand a little bit more about on the situation of dart:mirrors.
I understood from this issue that right now dart:mirrors shouldn't be used in any critical case. I'm really fond of using reflection both for backend and object serialization (dartson-like) but I'm a little bit concerned about the current state of the library since as stated by @mraleph there is not a way to get the shape of a record for example.
Can you give a more detailed update on what plans dart has for this specific library for example if it will be discontinued in a more permanent way in the near future or if the team is trying to provide an alternative?
jakemac53 commentedon Feb 23, 2024
I can't speak with authority, I do not control such things, but I believe it is unlikely it would be removed in a non-breaking Dart language release (so, Dart 4 at the earliest). But, it also is unlikely to get many improvements such as knowledge about record types. It has always been an experimental/unstable API and never graduated to full support. We strive mostly not to break the existing use cases, until such time as there is a viable replacement. This issue exists primarily as a way to track those use cases that exist, such that we can make decisions in the future about the support of this API, as well as the features needed to make any replacement a viable one.
lrhn commentedon Feb 26, 2024
I wouldn't say that
dart:mirrorshas always been experimental. In Dart 1, it was fully supported, also on the web.That was at a significant cost, though, which was why one was strongly discouraged from actually using it on the web, and if you did, there were annotations that allowed some tree-shaking to happen anyway. It still broke tree-shaking in general and required extra metadata, so if just one corner of your web app uses it, your deployment size could grow a lot.
Rather than worry about that, it was discontinued on the web, and never supported in AoT, and because of that
dart:mirrorshas not had any further development since about Dart 2.0. That's when it became "effectively unsupported". New compilers didn't need to support it, new platforms (including Flutter) didn't.It's a feature that only works on the JIT compiled VM, and only really with features that existed in Dart 2.0. That means you can use it for scripts (if you don't AoT compile them), and not much else.
Using reflection in tests means that those tests cannot be run AoT compiled, which means they are not testing the code that's actually going to run in production. (Can't do
dart test -c exe.)You can use
dart:mirrorstoday, but you shouldn't.They only work in stand-alone programs that you can control how gets run.
They should never leak into other people's code, or be run by any system that migth one day want to compile the code to exe first.
I do hope that macros can give users what they need to replace existing uses of reflcection. Like a
reflectiveTestthat finds all methods with a name starting withtest, a macro could find the same methods, and create anallTests()method that calls them one by one.sigurdm commentedon Feb 26, 2024
https://codereview.chromium.org//61793006 marked it as "unstable" - that was 2013
The documentation (today) says: This library is only supported by the Dart VM and only available on some platforms.
lrhn commentedon Feb 26, 2024
True, I guess the API was never considered stable, which makes sense if it has to match an evolving language.
The phrasing there was "API might change slightly as a result of user feedback", which is far from "this doesn't work". And the comment should have been removed if such changes didn't appear soon after.
The API at the time was supported everywhere.
And the API has been stable, so the comment didn't end up meaning much.
Mirrors, as such, were not considered experimental in Dart 1. The concrete API was, possibly, conisdered a little experimental, but after surviving a few releases, that disclaimer didn't mean much.
jakemac53 commentedon Feb 26, 2024
Right, macros can definitely enable these class based test runners. It could pretty easily even just be a small layer on top of package:test, since tests/groups can be added programatically.
gmpassos commentedon Feb 26, 2024
Macros will need to be able to inform the annotations of classes and methods or use them as filters and input parameters for generators.
lrhn commentedon Aug 20, 2024
Automatically generating code is what macros is intended to answer.
A
toJsonmacro is the first macro being built for the the feature, so it should be able to support that.Dart is not JavaScript, not everything can be converted to JSON, or a map. In some cases, choosing a good representation is non-trivial, and a naive conversion could be disasterous for performance. One size will not fit all.
Building one design into the compiler risks that design not being what people want, and what people want may change over time. A feature needs to be either so complete and configurable that you can use it for everything, or it needs to be optional, so it doesn't matter if it becomes obsolete.
bradcypert commentedon Jan 30, 2025
With the macros project being suspended, whats the plan for Reflection? I still dont find build runner sufficient (and its a pain to use imo).
[-]Request for feedback: Discontinuing support for dart:mirrors[/-][+]INTENT TO DEPRECATE: dart:mirrors[/+]chore(html): remove dart:mirrors usage in test/tokenizer_test.dart (#…
chore(unified_analytics): remove dart:mirrors usage in test/event_tes…
[-]INTENT TO DEPRECATE: dart:mirrors[/-][+]dart:mirrors deprecation and discontinuation[/+]Remove dart:mirrors and deprecate dom_model.dart and forwarder.dart (#…