Flutter › Flutter Riverpod Code Generation & Providers

How do provider dependencies and provider composition work in Riverpod, letting one provider genuinely and cleanly depend on the current value of a completely separate other provider?

Intermediate

Answer

Riverpod providers can genuinely and cleanly depend on one another simply by calling ref.watch or ref.read on that other required provider from directly within their own defining function body, and Riverpod automatically and correctly handles rebuilding a given dependent provider whenever any of its own underlying watched dependencies actually change, letting you cleanly compose together several smaller, individually focused providers into more genuinely complex derived state, such as a filtered product list provider that itself properly depends on both a full raw product list provider and a genuinely separate current search query provider.
final filteredProductsProvider = Provider<List<Product>>((ref) {
  final products = ref.watch(productsProvider);
  final query = ref.watch(searchQueryProvider);
  return products.where((p) => p.name.contains(query)).toList();
});
Real-world example A product search screen composes a filteredProductsProvider that automatically and cleanly recomputes itself whenever either the underlying full product list or the current user entered search query actually changes, without requiring any manual, error prone coordination logic written directly within the actual widget code itself.

Common follow-ups: How does Riverpod actually avoid genuinely unnecessary, wasteful recomputation when a dependency technically changes but the actual final derived resulting value genuinely stays exactly the same?;Can a provider genuinely depend on several entirely separate other providers together at the exact same time?