Sparround

Riverpod code generation (@riverpod)

Riverpod can be written two ways: by hand (you declare the provider yourself) and with code generation (you write a function/class with the @riverpod annotation and the provider is generated).

Setup, per the official docs:

  • Dependencies: flutter_riverpod and riverpod_annotation.
  • Dev dependencies: riverpod_generator and build_runner.
  • Generation: dart run build_runner watch -d.
  • The file needs a part 'file.g.dart'; directive at the top.
  • riverpod_lint is not part of the core installation — it is an optional lint tool configured through analysis_options.yaml.

The annotation picks the provider type for you: no manual choice between Provider, FutureProvider and StreamProvider — the function's signature decides. For a function named myFunction, a myFunctionProvider is generated.

dart
// ---------- Əl ilə ----------
final todoRepositoryProvider = Provider<TodoRepository>((ref) {
  return TodoRepository(ref.watch(apiClientProvider));
});

final todosProvider =
    AsyncNotifierProvider<TodosNotifier, List<Todo>>(TodosNotifier.new);

// family: yalnız bir pozisional arqument
final productProvider = FutureProvider.family<Product, String>(
  (ref, id) => ref.watch(catalogRepositoryProvider).fetch(id),
);

// ---------- Codegen ----------
// fayl: todos.dart
part 'todos.g.dart';

@riverpod
TodoRepository todoRepository(Ref ref) {
  return TodoRepository(ref.watch(apiClientProvider));
}

@riverpod
class Todos extends _$Todos {
  @override
  Future<List<Todo>> build() => ref.watch(todoRepositoryProvider).fetchAll();

  Future<void> add(String title) async { /* ... */ }
}

// Parametrlər adi funksiya arqumentləridir: adlı, opsional, default dəyərli.
@riverpod
Future<List<Product>> search(
  Ref ref, {
  required String query,
  int page = 1,
}) {
  return ref.watch(catalogRepositoryProvider).search(query, page: page);
}

// İstifadə: ref.watch(searchProvider(query: 'telefon'));

The same provider: by hand and with codegen.

CriterionWith codegenWithout codegen
Choosing the provider typeAutomatic — inferred from the signatureChosen by hand
Parameters (family)Named, optional, defaulted — unrestrictedOne positional argument
autoDisposeOn by default; disabled with `@Riverpod(keepAlive: true)`Specified explicitly
Hot reloadPer the docs, stateful hot reload of Riverpod code is supportedOrdinary Flutter hot reload
Build timeGrows — the docs note codegen "is still fairly slow"No extra step

The docs' honest recommendation: code generation brings many benefits but is still fairly slow; so it makes sense to adopt when you already run codegen for other packages (freezed, json_serializable), rather than introducing it on its own. A good citation for a balanced position in an interview.

📚 Sources and documentation