Intermediate · State management · topic 29 of 50 · 30 min
Riverpod overview
Explanation
Why Riverpod?
Provider is simple, but it depends on the widget tree: reading a provider that is not above you fails at run time, and two providers of the same type are awkward. Riverpod, created by the same author (Remi Rousselet), fixes these: providers are declared once as top-level definitions, missing providers are compile errors rather than run-time crashes, and state can be read and tested without a BuildContext.
The core pieces
| Piece | Role |
|---|---|
| ProviderScope | Wraps the app; stores the state of all providers |
| Provider | Exposes a value that does not change by itself (a repository, a formatter) |
| NotifierProvider + Notifier | Holds state that changes through methods (a cart, a counter) |
| FutureProvider / AsyncNotifierProvider | Loads async data and exposes AsyncValue: loading, error or data |
| ref.watch / ref.read | Listen and rebuild / read once in callbacks |
| ConsumerWidget | A widget that receives a WidgetRef to read providers |
Providers in Riverpod are lazy and cached: a provider runs only when something first reads it, and its value is kept while something is listening. Providers can also read other providers with ref.watch inside their own definition, so a cart total provider can depend on the cart provider and update whenever the cart changes.
A counter with a Notifier
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class CartCount extends Notifier<int> {
@override
int build() => 0; // initial state
void add() => state = state + 1; // assigning state notifies listeners
}
final cartCountProvider = NotifierProvider<CartCount, int>(CartCount.new);
void main() => runApp(const ProviderScope(child: MaterialApp(home: CartScreen())));
class CartScreen extends ConsumerWidget {
const CartScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(cartCountProvider);
return Scaffold(
body: Center(child: Text('Items: $count')),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(cartCountProvider.notifier).add(),
child: const Icon(Icons.add),
),
);
}
}Async data with FutureProvider
final weatherProvider = FutureProvider<String>((ref) async {
await Future.delayed(const Duration(seconds: 1)); // pretend API call
return 'Pune: 31°C';
});
class WeatherText extends ConsumerWidget {
const WeatherText({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final weather = ref.watch(weatherProvider);
return weather.when(
data: (w) => Text(w),
loading: () => const CircularProgressIndicator(),
error: (e, st) => Text('Could not load: $e'),
);
}
}Code generation (optional)
Riverpod also offers an optional code-generation style with @riverpod annotations and the riverpod_generator package, which writes provider declarations for you. Many teams use it; it is not required to start. Riverpod 3.0 (released in 2025) changed and simplified several APIs, and older tutorials may use outdated names such as StateNotifierProvider; follow riverpod.dev for current syntax.
Common mistakes
- Forgetting ProviderScope at the root: an error on the first read.
- Using ref.watch inside callbacks: use ref.read there.
- Mutating state in place (state.add(item)) in a Notifier: listeners are not notified. Assign a new value (state = [...state, item]).
- Copying old Riverpod 1.x/2.x tutorials without checking the current API.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Riverpod overview · 1/6
Riverpod is by the author of Provider. It is compile safe, testable and does not depend on the widget tree.
Prefer a video by a teacher? Find free videos on “riverpod tutorial notifier provider consumerwidget asyncvalue” on YouTube ↗
In real life: A city weather card that loads itself
A farming advice app shows the weather for the farmer's district at the top of the home screen. A FutureProvider calls the weather API; the card uses weather.when to show a spinner, the result, or a friendly error. Pull-to-refresh calls ref.invalidate(weatherProvider) to load fresh data. Tests override the provider with fake data, without any network.
// Refresh:
RefreshIndicator(
onRefresh: () => ref.refresh(weatherProvider.future),
child: ListView(children: const [WeatherText()]),
)Practice (0/3 done)
What must wrap a Riverpod app?
In a Notifier<List<String>>, which update notifies listeners correctly?
Rebuild the Provider cart from the previous topic with Riverpod: a Notifier<List<CartItem>> with add and clear, a NotifierProvider, ConsumerWidgets for the badge and the cart screen, and a FutureProvider that "loads" products after a delay with loading and error states. Follow the syntax on riverpod.dev for the version you install.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Bloc, Cubit and choosing an approachState management · same module
- What state is, and setStateState management · same module
- Interview questions: FlutterFlutter careers and interviews
- Flutter jobs and freelancing in IndiaFlutter careers and interviews
- async and awaitJavaScript Programming (language in depth) · Asynchronous JavaScript
- Parameters in depth: optional, named, ref, out, params, overloadingC# and .NET · Decisions, loops and methods
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Who created Riverpod?
Answer: The author of Provider
Remi Rousselet created both.
What does AsyncValue.when require you to handle?
Answer: data, loading and error
All three states.
Which widget type gives you a WidgetRef in build?
Answer: ConsumerWidget
build(BuildContext context, WidgetRef ref).
Why check riverpod.dev before copying an old tutorial?
Answer: APIs changed across major versions, including Riverpod 3
Use current syntax.
Which object holds a StatefulWidget's State between rebuilds?Related
Which class do Provider models usually extend?Related
Answer: ChangeNotifier
ChangeNotifier has addListener and notifyListeners.
What should you do before starting a freelance app project?Related
Answer: Agree a written scope, timeline and payment milestones
Clear scope prevents disputes.
What is good advice about state management choices?Related
Answer: Pick one, learn it well, use it consistently
Consistency matters most.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 1 more topic in “State management” before its exam: Bloc, Cubit and choosing an approach.
- Module 7 exam: State management · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Networking, storage and Firebase. 50 topics left in the course before the final exam.