Blog
Dart Null Safety: A Complete Migration Guide
What is Null Safety?
Null safety is a major Dart language feature that helps prevent null reference errors at compile time, making your code more robust and reliable.
It’s designed to eliminate the “billion-dollar mistake” — null pointer exceptions.
Core Concepts
- Non-nullable by default: Variables can’t be null unless explicitly declared.
- Nullable types: Use
?to make types nullable. - Null-aware operators: Safe ways to handle potentially null values.
- Flow analysis: Dart tracks null safety through control flow.
Here’s a quick comparison:
| Feature | Null Safe Dart | Legacy Dart |
|---|---|---|
| Non-nullable variables | ✅ Enforced | ❌ Not enforced |
| Nullable types | String? | String (could be null) |
| Null checks at compile time | ✅ | ❌ |
| Operators for null safety | ?., ??, ??=, ! | Limited |
Basic Syntax Changes
Non-nullable Types
// Old way (unsafe)
String name;
int age;
// New way (null safe)
String name = ''; // Must be initialized
int age = 0; // Must be initialized
// Or use late for lazy initialization
late String name;
late int age;
Nullable Types
// Nullable variables
String? name; // Can be null
int? age; // Can be null
List<String>? items; // Can be null
// Nullable function parameters
void printName(String? name) {
if (name != null) {
print(name.toUpperCase());
}
}
Null-Aware Operators
Null Check Operator (?.)
String? name;
int length = name?.length ?? 0; // Safe access, returns 0 if null
Null Assignment Operator (??=)
String? name;
name ??= 'Anonymous';
print(name); // 'Anonymous'
Null Assertion Operator (!)
String? name = getName();
String upperName = name!.toUpperCase(); // Assert non-null
⚠️ Caution: Use ! sparingly — only when you are certain the value isn’t null.
Migration Process
Step 1: Update Dependencies
Update your pubspec.yaml and ensure all dependencies support null safety:
dependencies:
flutter:
sdk: flutter
Check outdated or unsafe dependencies:
dart pub deps --json | dart pub outdated --json
Step 2: Migrate Your Code
Before Migration:
class User {
String name;
int age;
List<String> hobbies;
User(this.name, this.age, this.hobbies);
void addHobby(String hobby) {
hobbies.add(hobby);
}
}
After Migration:
class User {
final String name;
final int age;
final List<String> hobbies;
const User({
required this.name,
required this.age,
required this.hobbies,
});
void addHobby(String hobby) {
hobbies.add(hobby);
}
}
Common Patterns
Optional Parameters
void createUser({
required String name,
int? age,
String? email,
List<String>? hobbies,
}) {
final userAge = age ?? 0;
final userEmail = email ?? 'no-email@example.com';
final userHobbies = hobbies ?? <String>[];
}
Factory Constructors
class ApiResponse<T> {
final T? data;
final String? error;
final bool success;
const ApiResponse._({
this.data,
this.error,
required this.success,
});
factory ApiResponse.success(T data) {
return ApiResponse._(data: data, success: true);
}
factory ApiResponse.error(String error) {
return ApiResponse._(error: error, success: false);
}
}
Best Practices
✅ Prefer non-nullable types whenever possible ✅ Use required parameters for clarity ✅ Handle null gracefully with defaults and null-aware operators
Example:
String getUserDisplayName(User? user) {
return user?.name ?? 'Anonymous User';
}
Testing Null Safety
Unit tests can validate null-safe behavior:
void main() {
group('Null Safety Tests', () {
test('should handle null values correctly', () {
String? name;
expect(name?.length, isNull);
expect(name ?? 'default', equals('default'));
});
test('should work with nullable collections', () {
List<String>? items;
expect(items?.isEmpty, isNull);
items = [];
expect(items?.isEmpty, isTrue);
});
});
}
Conclusion
Dart null safety is a powerful upgrade that:
- Eliminates entire classes of runtime errors
- Improves developer confidence
- Makes APIs clearer and more reliable
➡️ Start migration with small, isolated parts of your codebase.
➡️ Use Dart’s migration tools.
➡️ Remember: null safety isn’t just about adding ? and ! — it’s about designing APIs that communicate intent clearly.
Enjoyed this? Share it, or reply by email — comments are retired here to keep the site fast and low-maintenance.