riverpod
Use when setting up providers, combining requests, managing state disposal, passing arguments, performing side effects, or testing providers (Riverpod).
Install / Use
npx skills add evanca/flutter-ai-rules --skill riverpodInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
Development & EngineeringSupported Platforms
Our assessment of riverpod
riverpod scores 90/100 on our quality scale, 1161st of 4,634 Development & Engineering skills we index (top 26%).
Its SKILL.md is 6.9 KB long, well organised into 12 sections with 10 code examples: a thorough specification that gives an agent plenty to work with.
It has 646 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 19 days ago, so riverpod is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
riverpod compared with similar skills
All 4 of these similar skills score higher than riverpod; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| riverpod (this skill)by evanca | 90 | 646 | 19d ago | SKILL.md |
| ai-job-searchby MadsLorentzen | 100 | 44.9k | today | CLAUDE.md |
| claude-howtoby luongnv89 | 100 | 41.7k | 3d ago | CLAUDE.md |
| algorithmic-artby anthropics | 100 | 177.9k | 11d ago | SKILL.md |
| pptxby anthropics | 100 | 177.9k | 11d ago | SKILL.md |
Frequently asked questions
- How do I install riverpod?
- Run
npx skills add evanca/flutter-ai-rules --skill riverpod. The install tabs above show the steps for each supported agent. - Which AI agents does riverpod work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is riverpod safe to use?
- It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is riverpod still maintained?
- The repository was last updated 19 days ago, so riverpod is actively maintained.
Skill content
View source on GitHubname: riverpod description: "Use when setting up providers, combining requests, managing state disposal, passing arguments, performing side effects, or testing providers (Riverpod)." license: MIT
Riverpod Skill
This skill defines how to correctly use Riverpod for state management in Flutter and Dart applications.
1. Setup
void main() {
runApp(const ProviderScope(child: MyApp()));
}
- Wrap your app with
ProviderScopedirectly inrunApp— never insideMyApp. - Install and use
riverpod_lintto enable IDE refactoring and enforce best practices.
2. Defining Providers
// Functional provider (codegen)
@riverpod
int example(Ref ref) => 0;
// FutureProvider (codegen)
@riverpod
Future<List<Todo>> todos(Ref ref) async {
return ref.watch(repositoryProvider).fetchTodos();
}
// Notifier (codegen)
@riverpod
class TodosNotifier extends _$TodosNotifier {
@override
Future<List<Todo>> build() async {
return ref.watch(repositoryProvider).fetchTodos();
}
Future<void> addTodo(Todo todo) async { ... }
}
- Define all providers as
finaltop-level variables. - Use
Provider,FutureProvider, orStreamProviderbased on the return type. - Use
ConsumerWidgetorConsumerStatefulWidgetinstead ofStatelessWidget/StatefulWidgetwhen accessing providers.
3. Using Ref
| Method | Use for |
|---|---|
| ref.watch | Reactively listen — rebuilds when value changes. Use during build phase only. |
| ref.read | One-time access — use in callbacks/Notifier methods, not in build. |
| ref.listen | Imperative subscription — prefer ref.watch where possible. |
| ref.onDispose | Cleanup when provider state is destroyed. |
// In a widget
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final value = ref.watch(myProvider);
return Text('$value');
}
}
// Cleanup in a provider
final provider = StreamProvider<int>((ref) {
final controller = StreamController<int>();
ref.onDispose(controller.close);
return controller.stream;
});
- Never call
ref.watchinside callbacks, listeners, or Notifier methods. - Use
ref.read(yourNotifierProvider.notifier).method()to call Notifier methods from the UI. - Check
context.mountedbefore usingrefafter anawaitin async callbacks.
4. Combining Providers
@riverpod
Future<String> userGreeting(Ref ref) async {
final user = await ref.watch(userProvider.future);
return 'Hello, ${user.name}!';
}
- Use
ref.watch(asyncProvider.future)to await an async provider's resolved value. - Providers only execute once and cache the result — multiple widgets listening to the same provider share one computation.
5. Passing Arguments (Families)
@riverpod
Future<Todo> todo(Ref ref, String id) async {
return ref.watch(repositoryProvider).fetchTodo(id);
}
// Usage
final todo = ref.watch(todoProvider('some-id'));
- Always enable
autoDisposefor parameterized providers to prevent memory leaks. - Use
Dart 3 recordsor code generation for multiple parameters — they naturally override==. - Avoid passing plain
ListorMapas parameters (no==override); useconstcollections, records, or classes with proper equality. - Use the
provider_parameterslint rule fromriverpod_lintto catch equality mistakes.
6. Auto Dispose & State Lifecycle
- With codegen: state is destroyed by default when no longer listened to. Opt out with
keepAlive: true. - Without codegen: state is kept alive by default. Use
.autoDisposeto enable disposal. - State is always destroyed when a provider is recomputed.
// keepAlive with timer
ref.onCancel(() {
final link = ref.keepAlive();
Timer(const Duration(minutes: 5), link.close);
});
- Use
ref.onDisposefor cleanup; do not trigger side effects or modify providers inside it. - Use
ref.invalidate(provider)to force destruction; useref.invalidateSelf()from within the provider. - Use
ref.refresh(provider)to invalidate and immediately read the new value — always use the return value.
7. Eager Initialization
Providers are lazy by default. To eagerly initialize:
// In MyApp or a dedicated widget under ProviderScope:
Consumer(
builder: (context, ref, _) {
ref.watch(myEagerProvider); // forces initialization
return const MyApp();
},
)
- Place eager initialization in a public widget (not
main()) for consistent test behavior. - Use
AsyncValue.requireValueto read data directly and throw clearly if not ready.
8. Performing Side Effects
@riverpod
class TodosNotifier extends _$TodosNotifier {
Future<void> addTodo(Todo todo) async {
state = const AsyncLoading();
state = await AsyncValue.guard(() async {
await ref.read(repositoryProvider).addTodo(todo);
return [...?state.value, todo];
});
}
}
// In UI:
ElevatedButton(
onPressed: () => ref.read(todosNotifierProvider.notifier).addTodo(todo),
child: const Text('Add'),
)
- Use
ref.read(notref.watch) in event handlers. - After a side effect, update state by: setting it directly, calling
ref.invalidateSelf(), or manually updating the cache. - Always handle loading and error states in the UI.
- Do not perform side effects in provider constructors or build methods.
9. Provider Observers
class MyObserver extends ProviderObserver {
@override
void didUpdateProvider(ProviderObserverContext context, Object? previousValue, Object? newValue) {
print('[${context.provider}] updated: $previousValue → $newValue');
}
@override
void providerDidFail(ProviderObserverContext context, Object error, StackTrace stackTrace) {
// Report to error service
}
}
runApp(ProviderScope(observers: [MyObserver()], child: MyApp()));
10. Testing
// Unit test
final container = ProviderContainer(
overrides: [repositoryProvider.overrideWith((_) => FakeRepository())],
);
addTearDown(container.dispose);
expect(await container.read(todosProvider.future), isNotEmpty);
// Widget test
await tester.pumpWidget(
ProviderScope(
overrides: [repositoryProvider.overrideWith((_) => FakeRepository())],
child: const MyApp(),
),
);
- Create a new
ProviderContainerorProviderScopefor each test — never share state between tests. - Use
container.listenovercontainer.readforautoDisposeproviders to keep state alive during the test. - Use
overridesto inject mocks or fakes. - Prefer mocking dependencies (repositories) rather than Notifiers directly.
- If you must mock a Notifier, subclass the original — don't use
implementsorwith Mock. - Place Notifier mocks in the same file as the Notifier if using code generation.
- Obtain the container in widget tests with
ProviderScope.containerOf(tester.element(...)).
References
Related Skills
ai-job-search
44.9kThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.
claude-howto
41.7kA visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
pptx
177.9kUse this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an em…
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
