Non-Nullable Dart: Understanding Null Safety

Learn how to use null safety in Dart. Get to know Dart’s type system and how to utilize language features in production code. By Sardor Islomov.

Leave a rating/review
Download materials
Save for later

Null safety helps you solve one of the most common errors in software development: NullPointerException. This exception and other types of bugs cost millions of dollars for businesses and corporations. As a result, many companies recruit developers with good error-handling skills.

Null safety is not a new concept. Other languages such as Swift, Kotlin and Rust, have implemented null safety based on their type systems and language features. Dart has also recently introduced sound null safety.

In this tutorial, you’ll build ProfileApp, a small app that saves data about users and their relationships. In the process, you’ll learn about:

  • Sound null safety.
  • How to create a Flutter app with null-safe code.
  • The type system in Dart.
  • How to work with nullable types.
  • What type promotion is and how Dart automatically promotes types.
  • The migration types you can use to make your existing code null safe.
Note: This tutorial assumes you have experience with Dart and Flutter widgets. If you don’t, check out this Flutter UI widgets video course and our Getting Started With Flutter tutorial.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial. After the download completes, unzip the file to a suitable location.

Note: This tutorial uses Android Studio, but feel free to use any editor that supports the Flutter SDK and Dart. If you use a different editor, however, keep in mind that some screenshots are specific to Android Studio, so they might vary from what you see on your screen.

ProfileApp consists of two screens and one dialog. In the first screen, the user enters their own data. In the second, they can add relatives or friends based on their preferences. Finally, users can review the entered data in the dialog widget. Follow the instructions in the next section to try the app out for yourself.

Getting to Know the App

Open the starter project in Android Studio by clicking Open an Existing Project in the Welcome to Android Studio window:

Open an Existing Project in Android Studio

Browse to the location where you unzipped the file. Choose the starter folder and click Open:

Choose starter project

The project structure should look like this:

Project structure

The project already contains most of the UI code. You’ll concentrate on using model classes to save user-entered data and integrating that data into the existing UI components.

Inside Android Studio, open the terminal and enter flutter pub get to get all the packages:

Run flutter pub get

Build and run the app. You’ll see the home page:

Home Page with empty information

Tapping the + button opens the Add member page. You can add friends or family members here:

Add member page with text fields to enter details about friends and family members

Go back to the previous screen. Tap the Save & Preview button and the User details dialog appears:

Empty Profile Dialog

Right now, you can add people, but they don’t appear on the home page. Furthermore, the dialog is missing some information. You’ll fix these issues using null-safe code. Next, you’ll learn about what sound null safety is.

Understanding Sound Null Safety

Null is just the absence of a value for an object, which Dart needs to be able to represent. null helps developers deal with the unknown in their code.

When any exception is not handled, the app will show a red error screen. If you try to call a method or getter on a null object, Dart will throw a NoSuchMethodError. This is essentially the same as a NullPointerException from other languages such as Java. For the purposes of this article, the term NullPointerException (NPE) will be used to discuss null errors since it is the more commonly used term.

The main issue with the NullPointerException is that it can happen at almost any part of the app if not well handled. Checking for nulls every now and then throughout your app isn’t the best either. For these reasons and more, handling nulls at the language level is probably the best way to avoid the dreaded NullPointerEception.

To build on this idea, the Dart team introduced sound null safety. This means that variables are considered non-nullable by default. If you don’t give an object null support when you create it, it will never get a null. As a result, you avoid null reference errors in your code.

Before going into details about null safety and how it works, you have to understand the type system in Dart. The Dart team relied on the type system when they implemented null safety.

Exploring the Dart Type System

Dart divides types into two groups:

  • Nullable types
  • Non-Nullable types

Nullable types can contain either a value or null. There are certain types of operators that help you work with nullable types. The figure below is an example representing a nullable String:

Nullable Strings can contain either a String or null

Non-Nullable types can only contain values. Nulls are not permitted.

Non-nullable Dart Strings can only contain String values

The type hierarchy of Dart is as follows: Object? is at the top and Never is at the bottom. You’ll rarely use Never, though. Any code that returns or evaluates to Never either throws an exception or aborts the program.

Nullable Type system in Dart

Now that you know what null safety is, you need to enable it before you can work with it.

Enabling Null Safety

Dart introduced a stable version of null safety in version 2.12.0. On the terminal, you can run flutter –version to verify your version is at least up to version 2.12.0. Alternatively, you can simply follow the steps below to download the latest release from the stable channel.

In the terminal, run the flutter channel command to check which channel you are currently using:

Example of the result of a Flutter channel command, showing the Beta channel with an asterisk next to it

Run the flutter channel stable command to switch to the stable channel:

Change Flutter channel command showing the result: Switched to branch 'Stable'

Update to the latest version by running the flutter upgrade command:

Flutter Upgrade after channel switch

Open pubspec.yaml and confirm your SDK version under the environment section looks like below:

  sdk: ">=2.12.0 <3.0.0"

This changes the Dart version to 2.12.0.

Finally, run flutter upgrade again to avoid future problems with Android Studio:

Flutter Upgrade after changing version

Congratulations! You’ve just migrated your project to null safety. You can now use null safety in your project.

Migrating to Null-Safe Dart

Dart introduced null safety in 2.12.0, but there are old Dart codes in production. Since the Dart team can’t migrate your code automatically. You have two options:

  1. Migrate using a tool that makes easily predictable changes for you. Based on your needs, you can choose to apply those changes or not.
  2. Migrate manually, where you can easily predict most of the changes that need null safety and migrate accordingly. This involves manually refactoring your code.
Note: The Dart team provides migration guides to help you learn more about migrating your code to null safety.