Dart Tutorial

Dart Lesson 37 of 102 3 min read

Null Safety in Dart: Nullable and Non-Nullable Types

Learn sound null safety in Dart: what null is, nullable types with ?, type promotion, and how the compiler prevents null errors.

On this page

null means “no value”. It is useful: a user may have no middle name, a search may find nothing. The danger comes from forgetting that a value might be missing and using it anyway.

Dart’s answer is sound null safety: every type is non-nullable unless you say otherwise, and the compiler checks every use.

Non-nullable by default #

void main() {
  String name = 'Dart';
  // name = null; // error: null can't be assigned to String

  print(name.length); // always safe
}
4

Because name can never be null, name.length can never crash.

Allowing null with ? #

Add ? after a type to say the variable may hold null.

void main() {
  String? middleName;       // starts as null
  print(middleName);

  middleName = 'Kumar';
  print(middleName);

  int? age = null;
  print(age);
}
null
Kumar
null

String and String? are different types. Think of String? as “either a String or nothing”.

The compiler protects you #

You cannot call methods on a value that might be null.

void main() {
  String? city;

  // print(city.length);
  // error: 'length' can't be accessed because the receiver can be null

  print(city?.length); // safe: gives null instead of crashing
}
null

Type promotion: check, then use #

When you test that a variable is not null, Dart treats it as non-nullable from that point on. No extra syntax is needed.

void describe(String? city) {
  if (city == null) {
    print('No city given');
    return;
  }
  // From here, city is a String.
  print('${city.toUpperCase()} has ${city.length} letters');
}

void main() {
  describe(null);
  describe('Pokhara');
}
No city given
POKHARA has 7 letters

Promotion works for local variables, parameters and private final fields. For other fields, copy the value into a local variable first:

class Profile {
  String? bio;
}

void main() {
  var profile = Profile()..bio = 'Dart learner';

  final bio = profile.bio;
  if (bio != null) {
    print(bio.length);
  }
}
12

Nullable types in functions and collections #

String? findUser(int id) {
  const users = {1: 'Asha', 2: 'Bimal'};
  return users[id]; // null when the id is missing
}

void main() {
  print(findUser(1));
  print(findUser(9));

  List<String?> answers = ['yes', null, 'no']; // items may be null
  List<String>? maybeList;                     // the list itself may be null

  print(answers);
  print(maybeList);
}
Asha
null
[yes, null, no]
null

What “sound” means #

If a variable’s type is non-nullable, it is guaranteed never to be null, in every part of the program. Since Dart 3 this is always on. That guarantee lets the compiler remove hidden null checks, so null-safe code is also a little faster.

Good habits #

  • Make things non-nullable unless there is a real reason for them to be missing.
  • Prefer an empty list or an empty string to null when “nothing” and “empty” mean the same thing.
  • Handle the null case close to where the value arrives, then pass non-null values around.

The next lesson covers the operators that make working with nullable values short: ?., ??, ??= and !.

Try it yourself #

Write String greeting(String name, String? title) that returns Hello, Dr. Rai when a title is given and Hello, Rai when it is null. Use an if check and let type promotion do the work.

Practise in the playground Updated by Santosh Adhikari