Flutter Riverpod Expert
Apply Riverpod 3 patterns that fit the current codebase. In AuraVibes, prefer the existing hooks_riverpod setup for Flutter widgets instead of adding or recommending flutter_riverpod directly.
First Checks
- Inspect the package's
pubspec.yaml before suggesting imports or dependencies.
- In this repo, use:
package:hooks_riverpod/hooks_riverpod.dart for Flutter widgets, WidgetRef, ProviderScope, ProviderContainer, hooks, and consumer widgets.
package:riverpod_annotation/riverpod_annotation.dart for generated providers.
package:riverpod_annotation/experimental/scope.dart only when @Dependencies is required for scoped providers.
package:riverpod/experimental/mutation.dart only when using experimental Mutation.
package:hooks_riverpod/legacy.dart only when maintaining existing StateProvider, StateNotifierProvider, or ChangeNotifierProvider code.
- Do not manually edit
pubspec.yaml for dependency changes in this repo. Use the project command convention with fvm flutter pub add ....
- Run generation from the package directory after changing generated providers:
fvm dart run build_runner build --delete-conflicting-outputs
Load References
- Read
references/auravibes-riverpod.md before editing AuraVibes Riverpod code.
- Read
references/riverpod3-core.md for provider selection, Riverpod 3 behavior changes, lifecycle, async state, and testing.
- Read
references/hooks-riverpod.md when touching UI widgets, local widget state, hooks, HookConsumerWidget, or imports.
Default Decisions
- Keep state ownership in generated Notifier classes when state has user intents or mutations.
- Use generated function providers for pure computed values, repositories, services, one-shot fetches, and streams without public mutation methods.
- Use hooks for local widget-only state such as controllers, focus nodes, animation controllers, debounce timers, and form-local state.
- Use Riverpod for app/domain state shared across widgets, persisted across routes, injected into use cases, or consumed by tests.
- Prefer
ref.watch for reactive values, ref.select for narrow rebuilds, ref.read in event handlers and notifier methods, and ref.listen for side effects.
- Prefer
AsyncValue pattern matching or switch expressions for UI. The .when() method is PROHIBITED in new code. Avoid ad hoc isLoading/error flags unless a domain state object needs them for a specific UX.
- After
await inside notifier methods, check ref.mounted before touching ref or state if the notifier may have been disposed.
- Data mutations (CRUD) MUST use Riverpod
Mutation or an equivalent explicit mutation pattern. Manually toggling AsyncValue.loading() / AsyncValue.data() inside notifiers to track action state is PROHIBITED. build()-based AsyncNotifier MUST be reserved for state that genuinely needs initialization logic, not for wrapping simple action methods.
Avoid
- Do not recommend replacing
hooks_riverpod with flutter_riverpod in this repo.
- Do not add
flutter_riverpod just to access ConsumerWidget, WidgetRef, ProviderScope, or ProviderContainer; hooks_riverpod already provides the Flutter Riverpod API plus hooks support.
- Do not introduce legacy provider types for new state unless maintaining legacy code.
- Do not use
ref.read inside build to avoid rebuilds. Use ref.watch, ref.select, or split widgets.
- Do not watch providers inside large list builders when a row widget can watch its own item.
- Do not keep mutable app state in widgets if multiple features or screens need it.
- Do not make every provider
keepAlive: true; default generated providers are auto-dispose and that is usually correct.
- Do not use scoped providers without declaring
dependencies on scoped providers and generated dependents.
Common AuraVibes Pattern
This sample is based on ConversationSendQueue in apps/auravibes_app.
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'conversation_send_queue_notifier.g.dart';
class ConversationQueuedDraft {
const ConversationQueuedDraft({
required this.id,
required this.content,
});
final String id;
final String content;
}
@riverpod
class ConversationSendQueue extends _$ConversationSendQueue {
int _nextDraftId = 0;
@override
Map<String, List<ConversationQueuedDraft>> build() => {};
ConversationQueuedDraft enqueue({
required String conversationId,
required String content,
}) {
final draft = ConversationQueuedDraft(
id: 'queued-${_nextDraftId++}',
content: content,
);
state = {
...state,
conversationId: [...state[conversationId] ?? const [], draft],
};
return draft;
}
}
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class ChatInputWidget extends HookConsumerWidget {
const ChatInputWidget({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final isSending = ref.watch(sendMessageProvider.select((state) => state.isSending));
return IconButton(
onPressed: isSending
? null
: () => ref.read(sendMessageProvider.notifier).send(),
icon: const Icon(Icons.send),
);
}
}
Validation
- Run targeted tests from the package directory with
fvm flutter test <files> --no-pub.
- Run generation before analysis when provider signatures, annotations, file names, or provider names change.
- Run
fvm dart run melos analyze or the repo's focused validation command when the change affects shared providers.
Source: auravibes-apps/auravibes — distributed by TomeVault.
1---2name: flutter-riverpod-expert3description: Expert Riverpod 3 guidance for Flutter apps, especially projects using hooks_riverpod, flutter_hooks, riverpod_annotation, and riverpod_generator. Use when working with Riverpod providers, HookConsumerWidget/ConsumerWidget, WidgetRef/Ref, generated @riverpod providers, Notifier/AsyncNotifier/StreamNotifier, mutations, scoped providers, provider overrides, testing, caching, automatic retry, performance with select, or migrations from StateNotifier/ChangeNotifier/legacy providers. Use when this capability is needed.4---56# Flutter Riverpod Expert78Apply Riverpod 3 patterns that fit the current codebase. In AuraVibes, prefer the existing `hooks_riverpod` setup for Flutter widgets instead of adding or recommending `flutter_riverpod` directly.910## First Checks11121. Inspect the package's `pubspec.yaml` before suggesting imports or dependencies.132. In this repo, use:14 - `package:hooks_riverpod/hooks_riverpod.dart` for Flutter widgets, `WidgetRef`, `ProviderScope`, `ProviderContainer`, hooks, and consumer widgets.15 - `package:riverpod_annotation/riverpod_annotation.dart` for generated providers.16 - `package:riverpod_annotation/experimental/scope.dart` only when `@Dependencies` is required for scoped providers.17 - `package:riverpod/experimental/mutation.dart` only when using experimental `Mutation`.18 - `package:hooks_riverpod/legacy.dart` only when maintaining existing `StateProvider`, `StateNotifierProvider`, or `ChangeNotifierProvider` code.193. Do not manually edit `pubspec.yaml` for dependency changes in this repo. Use the project command convention with `fvm flutter pub add ...`.204. Run generation from the package directory after changing generated providers:21 `fvm dart run build_runner build --delete-conflicting-outputs`2223## Load References2425- Read `references/auravibes-riverpod.md` before editing AuraVibes Riverpod code.26- Read `references/riverpod3-core.md` for provider selection, Riverpod 3 behavior changes, lifecycle, async state, and testing.27- Read `references/hooks-riverpod.md` when touching UI widgets, local widget state, hooks, `HookConsumerWidget`, or imports.2829## Default Decisions3031- Keep state ownership in generated Notifier classes when state has user intents or mutations.32- Use generated function providers for pure computed values, repositories, services, one-shot fetches, and streams without public mutation methods.33- Use hooks for local widget-only state such as controllers, focus nodes, animation controllers, debounce timers, and form-local state.34- Use Riverpod for app/domain state shared across widgets, persisted across routes, injected into use cases, or consumed by tests.35- Prefer `ref.watch` for reactive values, `ref.select` for narrow rebuilds, `ref.read` in event handlers and notifier methods, and `ref.listen` for side effects.36- Prefer `AsyncValue` pattern matching or switch expressions for UI. The `.when()` method is PROHIBITED in new code. Avoid ad hoc `isLoading`/`error` flags unless a domain state object needs them for a specific UX.37- After `await` inside notifier methods, check `ref.mounted` before touching `ref` or `state` if the notifier may have been disposed.38- Data mutations (CRUD) MUST use Riverpod `Mutation` or an equivalent explicit mutation pattern. Manually toggling `AsyncValue.loading()` / `AsyncValue.data()` inside notifiers to track action state is PROHIBITED. `build()`-based `AsyncNotifier` MUST be reserved for state that genuinely needs initialization logic, not for wrapping simple action methods.3940## Avoid4142- Do not recommend replacing `hooks_riverpod` with `flutter_riverpod` in this repo.43- Do not add `flutter_riverpod` just to access `ConsumerWidget`, `WidgetRef`, `ProviderScope`, or `ProviderContainer`; `hooks_riverpod` already provides the Flutter Riverpod API plus hooks support.44- Do not introduce legacy provider types for new state unless maintaining legacy code.45- Do not use `ref.read` inside `build` to avoid rebuilds. Use `ref.watch`, `ref.select`, or split widgets.46- Do not watch providers inside large list builders when a row widget can watch its own item.47- Do not keep mutable app state in widgets if multiple features or screens need it.48- Do not make every provider `keepAlive: true`; default generated providers are auto-dispose and that is usually correct.49- Do not use scoped providers without declaring `dependencies` on scoped providers and generated dependents.5051## Common AuraVibes Pattern5253This sample is based on `ConversationSendQueue` in `apps/auravibes_app`.5455```dart56import 'package:riverpod_annotation/riverpod_annotation.dart';5758part 'conversation_send_queue_notifier.g.dart';5960class ConversationQueuedDraft {61 const ConversationQueuedDraft({62 required this.id,63 required this.content,64 });6566 final String id;67 final String content;68}6970@riverpod71class ConversationSendQueue extends _$ConversationSendQueue {72 int _nextDraftId = 0;7374 @override75 Map<String, List<ConversationQueuedDraft>> build() => {};7677 ConversationQueuedDraft enqueue({78 required String conversationId,79 required String content,80 }) {81 final draft = ConversationQueuedDraft(82 id: 'queued-${_nextDraftId++}',83 content: content,84 );8586 state = {87 ...state,88 conversationId: [...state[conversationId] ?? const [], draft],89 };9091 return draft;92 }93}94```9596```dart97import 'package:flutter/material.dart';98import 'package:hooks_riverpod/hooks_riverpod.dart';99100class ChatInputWidget extends HookConsumerWidget {101 const ChatInputWidget({super.key});102103 @override104 Widget build(BuildContext context, WidgetRef ref) {105 final isSending = ref.watch(sendMessageProvider.select((state) => state.isSending));106107 return IconButton(108 onPressed: isSending109 ? null110 : () => ref.read(sendMessageProvider.notifier).send(),111 icon: const Icon(Icons.send),112 );113 }114}115```116117## Validation118119- Run targeted tests from the package directory with `fvm flutter test <files> --no-pub`.120- Run generation before analysis when provider signatures, annotations, file names, or provider names change.121- Run `fvm dart run melos analyze` or the repo's focused validation command when the change affects shared providers.122123---124> Source: [auravibes-apps/auravibes](https://github.com/auravibes-apps/auravibes) — distributed by [TomeVault](https://tomevault.io).125<!-- tomevault:4.0:skill_md:2026-06-16 -->