Note:
The migration uses a new interactive algorithm designed specifically for Dart null safety.
Typical code migration tools are designed to be run once, handle most cases, and let the developer do manual cleanup on the result. This does not work well for null safety and attempting this workflow will result in a lot more manual work. Similarly, after your migration has been applied, the migration cannot be rerun without first reverting it.
Remember that Dart already has nullable types. Every type in old Dart code is nullable! What old Dart lacks is non-null types.
And like most migrations, our tool tries to preserve your code's current behavior. In the case of null safety, we may mark a lot of your types as nullable -- because they really were nullable before.
Nulls are traced through your program as far as they can go, and types are marked nullable in this process. If the tool makes a single mistake or choice you disagree with, it can lead to many excess nullable types.
Unintentional null is the top cause of crashes in Dart programs. By marking your intention with comments like /*?*/
and /*!*/
, we can stop these unintentional nulls from spreading through your program in your migrated code. Adding a small number of these hints will have a huge impact on migration quality.
The high level workflow of the tool is therefore driven through an interactive web UI. After starting the tool with dart migrate
, open the presented URL in a browser. Scan through the changes, use the “nullability trace” feature to find the best place to add a nullability hint (adding a hint in the best place can prevent dozens of types from being made nullable). Rerun the migration and repeat, committing the hints as you go. When the output is correct and acceptable, apply the migration.
For example,
List<int> ints = const [0, null]; int zero = ints[0]; int one = zero + 1; List<int> zeroOne = [zero, one];
The default migration will be backwards compatible, but not ideal.
List<int?> ints = const [0, null]; int? zero = ints[0]; int one = zero! + 1; List<int?> zeroOne = <int?>[zero, one];
zero
should not be marked nullable, but it is. We then have cascading quality issues, such as null-checking a value that shouldn't have been marked null, and marking other variables as null due to deep null tracing. We can fix this all by adding a single /*!*/
hint.
List<int?> ints = const [0, null]; int/*!*/ zero = ints[0]!; // Just add /*!*/ here, the migration tool does the rest! int one = zero + 1; List<int> zeroOne = <int>[zero, one];
If you add one hint before migrating, you have done the equivalent of making five manual edits after migrating. To find the best place to put your hints, use the preview tool‘s nullability trace feature. This lets you trace back up to the root cause of any type’s inferred nullability. Add hints as close to the original source of null as possible to have the biggest impact to the migration.
Note: The migration tool cannot be rerun on a migrated codebase. At that point in time, every nullable and non-nullable type is indistinguishable from an intentionally nullable or non-nullable type. The opportunity to change large numbers of types for you at once without also accidentally changing your intent has been lost. A long migration effort (such as one on a large project) can be done incrementally, by committing these hints over time.
Select a package to work on, and open a command terminal in the top-level of the package directory.
Run pub get
in order to make available all dependencies of the package.
It is best to migrate a package to null safety after the package‘s dependencies have migrated to null safety. Run pub outdated --mode=null-safety
to learn the migration status of the package’s dependencies. See the pub outdated documentation for more information.
It is best to migrate a package starting from a clean code repository state (git status
, for example), in case you must revert the migration. Ensure there are no pending changes in the package's code repository.
Run the migration tool from the top-level of the package directory:
dart migrate
The migration tool will display a URL for the web interface. Open that URL in a browser to view, analyze, and improve the proposed null-safe migration.
/*!*/
hint on a type. The tool has buttons to do this for you.pubspec.yaml
file, in order to change the Dart SDK version constraints, under the environment
field, and the “Package Config” file, located in the package’s .dart_tool
directory, named package_config.json
.Apply Migration
button in the interface.pub get
, then analyze and test your package.git checkout
).Please file issues at https://github.com/dart-lang/sdk/issues, and reference the analyzer-nnbd-migration
label (you may not be able to apply the label yourself).