Riverpod's code generation feature uses annotations and build_runner to automatically create providers with better type safety, performance, and developer experience.
Code generation offers several advantages over manual provider definitions:
Providers are automatically disposed when no longer needed, preventing memory leaks.
Generated providers have perfect type inference and catch errors at compile time.
Optimized provider implementations with minimal runtime overhead.
Write less code while getting more features like disposal, caching, and debugging.
The code generation process involves several steps that happen automatically when you run build_runner:
build_runner scans your code for @riverpod annotations and analyzes the function signatures.
The generator creates provider classes, handles disposal logic, and generates type-safe accessors.
Generated code is written to *.g.dart files that are imported via part directives.
See the difference between manual and generated providers:
final counterProvider = StateNotifierProvider<Counter, int>((ref) {
return Counter();
});
class Counter extends StateNotifier<int> {
Counter() : super(0);
void increment() => state++;
void decrement() => state--;
void reset() => state = 0;
}
// Usage: ref.watch(counterProvider);
// Access notifier: ref.read(counterProvider.notifier);@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state++;
void decrement() => state--;
void reset() => state = 0;
}
// Generated automatically:
// - counterProvider (the provider itself)
// - Auto-disposal when unused
// - Type-safe access patterns
// - Debug information and inspector supportUnderstanding what gets generated helps debug issues and optimize your providers:
// counter.dart
part 'counter.g.dart';
@riverpod
class Counter extends _$Counter {
// Your implementation
}
// counter.g.dart (Generated)
part of 'counter.dart';
final counterProvider = NotifierProvider<Counter, int>(Counter._);
class _$Counter extends Notifier<int> {
// Generated implementation with disposal, caching, etc.
}
// Plus debugging extensions and type definitionsThe typical development workflow with code generation:
Common issues and solutions:
Check that:
riverpod_generator in dev_dependenciespart directive is correctflutter clean and try againUsually means the generated file doesn't exist yet. Run dart run build_runner build to generate the missing files.
Use dart run build_runner build --delete-conflicting-outputs to resolve conflicts, but be careful as this deletes existing generated files.