With the release of Flutter 2.0, Google is also bringing Dart 2.12 to stable. In case you didn't know, Dart is the language that Flutter uses. It's a TypeScript-based language but comes with some language feature additions, including the ones I'm about to go over.

Null Safety

Null safety is a pretty great language feature. It forces you to consider whether a variable will ever be null, and explicitly deal with potential null situations, while also letting you guarantee that specific variables will never be null.

In Dart 2.12, there's now full support for null-safety, with a syntax similar to Swift and Kotlin. There's even smart-casting, where if Dart knows for sure that a normally-nullable variable can't be null, it will implicitly cast it to a non-nullable form.

Dart 2.12 non-nullable

Since null-safety is a (very) breaking change, this feature is opt-in. If you update to Dart 2.12, your compilation won't break, and you won't have to spend hours adding nullability hints to everything. You can even use null-safe dependencies if your project isn't yet null-safe.

Once you do decide to migrate, you can use the built-in migration tool (dart migrate) and/or the migration guide to get everything set up.

Also, while null-safety is included in Dart 2.12, if you create a new Flutter project, null-safety won't be enabled out of the box. You'll need to enable it manually. New Dart projects will have null-safety enabled.

Foreign Function Interface

Even though Dart (and Flutter's) focus is on full cross-platform compatibility, there are still some things that just need to be done natively. To make native operations easier, Dart has a foreign function interface, or FFI. The FFI lets you interact with C code from Dart without having to resort to weird string-based API calls or other clunky interoperability methods.

And with Dart 2.12, the FFI is now stable, meaning it's ready to be used in production projects and is mostly feature-complete.

With that in mind, there are some changes in the FFI, including a couple of breaking ones.

Most of the focus with this release was on how structs can be used with Dart and C. For one, you can now pass structs in your C code by reference and value, where previously only references were supported. Another important feature is support for nested structs, which wasn't present before this release.

Now for the breaking changes. If you were using the FFI, you may need to update your code to work with 2.12. With this version of FFI, you can no longer create empty structs. If you need one for some reason, you can use the new "Opaque" type. There are also some changes to how some of the FFI built-in functions work, which you can read about here.

Finally, there's a new package for the FFI that lets you generate FFI wrappers from existing C header files, called ffigen. If you have a lot of C code you need to use, with a lot of API methods, this will be pretty helpful. Even if the amount of C code you have is small, this is a nice convenience feature.


And that's pretty much it for Dart 2.12. With the addition of null-safety, and a stable C interoperability library, Dart is turning into a very feature-rich language. Let us know what you think about Dart 2.12 in the comments!