Null Safety
By Syncfusion®, Inc. · Last updated
What null is, how Dart stops null crashes, nullable types, the operators ?. ?? ??= and !, and late variables.
What Is Null Safety?
Null = "no value at all". An empty box.
Null safety = Dart's rule that a variable cannot be empty unless you say it may be.
For example:
String namemust always hold textString? nicknamemay hold text, or be empty (null)
Dart checks this before your program runs.
Simple lesson: with null safety, Dart knows which boxes may be empty, and makes you handle them.
A Real-World Example
A student asks the canteen for a samosa.
- The shopkeeper opens the box and hands one over.
- One day the box is empty, but nobody checked.
- The shopkeeper reaches in, finds nothing, and the order fails.
In older languages, using an empty value crashed the app the same way. Dart makes you check the box first, so this crash cannot happen by surprise.
Every Run box on this page runs on the course's Dart runner in your browser.
Some boxes fail on purpose, to show the errors null safety prevents.
What You Will Learn
In this lesson, you will learn:
- What null safety is and why Dart added it.
- Nullable and non-nullable types.
- The operators
?.,??,??=and!. lateandlate finalvariables.- The most common null mistakes, and how to avoid them.
Why Null Safety Was Introduced
The person who invented null, Tony Hoare, called it his "billion-dollar mistake".
The problem:
- Any variable could secretly be
null. - Using it, like
name.length, crashed the program while it ran. - These crashes often reached users, because nothing warned the programmer.
Dart's fix, added in 2021 and always on since Dart 3:
- A normal type can never be null. Dart checks it before running.
- A
?type may be null, and Dart makes you handle that case.
Simple lesson: null safety moves the "empty box" crash from your user's phone to your own screen, before the app ships.
Nullable vs Non-Nullable Types
Non-nullable type = a type that can never hold null: String, int, bool.
Nullable type = a type with ? after it, which can also hold null: String?, int?.
Non-Nullable: Never Empty
A String can never be null
void main() {
String name = null;
print(name);
}
Dart says: The value 'null' can't be assigned to a variable of type 'String' because 'String' is not nullable.
Nullable: Maybe Empty
A String? may be null
void main() {
String? nickname;
print(nickname);
nickname = 'Chintu';
print(nickname);
nickname = null;
print(nickname);
}
- A
String?with no value starts asnull. - It can switch between text and
null.
Compare the two kinds of types
Simple lesson: add ? only when a value can really be missing.
The Null Safety Rules
Rule 1: You Must Check Before You Use
This code is refused before it runs:
String? nickname;
print(nickname.length);
Dart says: The property 'length' can't be unconditionally accessed because the receiver can be 'null'.
In plain words: "This box may be empty. Check it first."
Rule 2: A Check Makes It Safe
Type promotion = after you check that a value is not null, Dart treats it as non-nullable.
Check first, then use
void main() {
String? nickname = 'Chintu';
if (nickname != null) {
print('Nickname has ${nickname.length} letters.');
} else {
print('No nickname.');
}
}
Inside the if block, Dart knows nickname is a String, so .length is allowed.
Rule 3: Non-Nullable Variables Need a Value Before Use
int total;
print(total);
Dart says: The non-nullable local variable 'total' must be assigned before it can be used.
Simple lesson: if a value may be null, check it, and Dart lets you use it after the check.
Null Safety Operators
Checking with if every time is long. Dart has four short operators.
Switch the value and watch all four:
Compare:
?.never crashes. It givesnullwhen the box is empty.??always gives a value. It uses'Guest'when the box is empty.!crashes when the box is empty.
?. Null-Aware Access
?. = "if it is not null, use it. If it is null, give null."
?. gives null instead of crashing
void main() {
String? nickname;
print(nickname?.length);
nickname = 'Chintu';
print(nickname?.length);
print(nickname?.toUpperCase());
}
?? Null Coalescing
?? = "use the left value, but if it is null, use the right value instead".
?? gives a default value
void main() {
String? nickname;
print('Hello, ${nickname ?? 'Guest'}!');
nickname = 'Chintu';
print('Hello, ${nickname ?? 'Guest'}!');
int? bonusMarks;
int total = 80 + (bonusMarks ?? 0);
print('Total: $total');
}
?? is perfect with tryParse() (see Data Types): int.tryParse(text) ?? 0.
??= Null-Aware Assignment
??= = "put this value in, but only if the variable is null right now".
??= fills only an empty box
! Null Assertion
! = "I promise this is not null." Dart believes you.
- If you are right, it works like a normal value.
- If you are wrong, the program crashes.
A broken promise crashes the program
void main() {
int? rollNumber;
print('Before the crash');
print(rollNumber! + 1);
}
The error is Null check operator used on a null value.
Use ! only when you are sure a value cannot be null, and Dart just cannot see why.
If you are not sure, use ?., ?? or an if check instead.
Simple lesson: ?. is safe access, ?? is a default, ??= fills an empty box, and ! is a risky promise.
Late Variables
late
late = "this non-nullable variable will get a value later, before I use it".
A late variable gets its value later
void main() {
late String greeting;
var hour = 9;
if (hour < 12) {
greeting = 'Good morning';
} else {
greeting = 'Good afternoon';
}
print(greeting);
}
greetingis aString, not aString?. It is never null.latetells Dart to trust you about when it gets its value.
If you read a late variable before giving it a value, real Dart crashes with a LateInitializationError.
late final
late final = gets a value later, and only once.
late final: set once, later
void main() {
late final String topper;
var scores = 92;
topper = scores > 90 ? 'Asha' : 'Ravi';
print('Topper: $topper');
}
Common Use Cases
- A value decided after some checks, like
greetingabove. - A value that is expensive to work out, and maybe not needed:
late final report = buildReport();runsbuildReport()only the first timereportis used. - Fields in classes that are set up after the object is made (see Classes).
In real Dart, late final x = work(); waits and runs work() only when x is first used.
In this course's runner, it runs straight away. The examples on this page do not depend on the waiting.
Simple lesson: late means "a real value is coming before I use it", so the type does not need ?.
Common Pitfalls
Avoiding Null Errors
- Prefer non-nullable types. Add
?only when a value can really be missing. - Give defaults with
??.name ?? 'Guest'always gives a value. - Check with
if (x != null). Dart then trusts the value inside the block. - Avoid
!. Every!is a possible crash. - Use
lateonly when you are sure the value will be set before it is read.
Easy way to remember
?on a type = "this box may be empty".?.= "peek, and give null if empty".??= "or else use this".!= "trust me", and a crash if you were wrong.
Simple lesson: most null bugs disappear when you use ?? and if checks instead of !.
TL;DR
- null = no value. Null safety = only
?types may be null. Non-nullable =
String, never null. Nullable =String?, may be null.- Check with
if (x != null)to use it. That is type promotion.
- Check with
Operators:
?.= use it, or givenull.??= a default value.??== assign only if null.!= "not null, I promise". Crashes if wrong.
late= a non-nullable variable that gets its value later.late final= later, and once.- Avoid null errors = prefer non-nullable types,
??and checks, and use!rarely.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
String name = null; | Any variable can be null | Use String? if it may be null | The value 'null' can't be assigned. |
nickname.length on a String? | Dart will just try it | Check first, or use ?. | can't be unconditionally accessed. |
! everywhere | ! fixes null errors | ! only hides them until the program runs | Null check operator used on a null value. |
? on everything | Nullable is safer | It forces checks everywhere | Long, messy code. |
Reading a late variable too early | late gives a default | You must assign it first | LateInitializationError. |
x ?? y when x cannot be null | ?? is always useful | It only helps nullable values | A warning, and dead code. |
Expecting ??= to replace a value | It always assigns | It assigns only when the value is null | The old value stays. |
Check Yourself
Exercises
What to Remember
- A normal type can never be null. Add
?when a value may be missing. - Check with
if (x != null), and Dart lets you use the value safely. ?.givesnullinstead of crashing, and??gives a default value.??=fills a variable only if it is null.!is a promise that crashes when wrong.latemeans a non-nullable value will be set before it is used.
Next: Conditional Statements. You will learn how a program makes decisions with if, else and switch.