From Provider to Riverpod: Migrating Legacy State
Convert existing ChangeNotifier and Provider code to Riverpod's compile-safe provider graph.
Why Migrate to Riverpod?
The classic provider package solved dependency injection in Flutter, but it has real weaknesses you have probably hit in production:
- Runtime crashes — calling
context.read<T>()for a type that was never provided throws aProviderNotFoundExceptionat runtime, not compile time. - BuildContext coupling — you can only read providers where you have a
BuildContext. - No combining — depending on one
ChangeNotifierfrom another is awkward and error-prone.
Riverpod is a rewrite by the same author. Providers are top-level globals that the compiler can verify, so a missing dependency becomes a compile error. This lesson walks you through migrating a legacy ChangeNotifier + Provider app to Riverpod 2.0, piece by piece.
The Legacy Code We Are Migrating
Here is a typical legacy counter feature using ChangeNotifier. It exposes a value and a method that calls notifyListeners(). This is the pattern we will convert step by step.
Notice that the state (_count) and the mutation logic live together inside a class that extends ChangeNotifier.
// LEGACY — provider package
import 'package:flutter/foundation.dart';
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void reset() {
_count = 0;
notifyListeners();
}
}All lessons in this course
- From Provider to Riverpod: Migrating Legacy State
- Code Generation with riverpod_generator and @riverpod
- AsyncNotifier and FutureProvider Data Pipelines
- Provider Scoping, Overrides, and ProviderObserver