Sparround

autoDispose, keepAlive and family

Riverpod's two most misunderstood modifiers concern the lifetime and the parameters of state.

autoDispose — clearing the state once no listener uses the provider. Per the docs, Riverpod tracks a listener count; when it reaches zero the provider is considered "not used". Then ref.onCancel fires immediately, Riverpod waits one frame, and if the provider is still unused ref.onDispose runs and the state is destroyed. For providers written with code generation this is enabled by default; you disable it with @Riverpod(keepAlive: true). For hand-written providers the 3.x docs show the isAutoDispose: true parameter.

family — the modifier that lets you pass arguments to a provider. Riverpod keeps separate state per argument, so the argument must be stable under ==/hashCode (value types, records, immutable models).

dart
// Kod generasiyası ilə: parametrlər funksiyanın arqumentləridir,
// autoDispose default olaraq aktivdir.
@riverpod
Future<Product> product(Ref ref, String id) {
  return ref.watch(catalogRepositoryProvider).fetch(id);
}

// İstifadə: hər id ayrı provider instansiyasıdır.
final product = ref.watch(productProvider('sku-42'));

// Kod generasiyası olmadan: family modifikatoru, bir pozisional arqument.
final productProviderManual = FutureProvider.family<Product, String>(
  (ref, id) => ref.watch(catalogRepositoryProvider).fetch(id),
);

// keepAlive: uğurlu nəticəni cache-də saxlamaq, xətanı saxlamamaq.
@riverpod
Future<Config> config(Ref ref) async {
  final result = await ref.watch(apiClientProvider).loadConfig();
  ref.keepAlive(); // yalnız uğurlu hala çatdıqda cache-i qoruyur
  return result;
}

family plus autoDispose: a separate cache per id, cleared when unused.

SituationRecommendationReason
The provider takes parameters (a family)Keep autoDispose enabledThe docs' recommendation: otherwise state accumulates for every argument combination
Configuration or auth needed app-wide`@Riverpod(keepAlive: true)`Reloading on every navigation makes no sense
A heavy request's result, but only when it succeedsautoDispose plus a conditional `ref.keepAlive()`Errors are not cached while successful results are
A screen's temporary state (a filter, a selection)autoDispose — or not a provider at allThe DO/DON'T page advises against providers for ephemeral state

ref.keepAlive() returns a link: calling link.close() restores the auto-dispose behaviour. So the cache can be kept conditionally rather than forever — for instance a Timer calling link.close() after five minutes to declare the data stale. That detail is a strong argument in an interview discussion about caching strategy.

Riverpod 3 adds one more mechanism: pause/resume. A subscription can be controlled manually with subscription.pause() and subscription.resume(), and per the docs subscriptions are paused automatically for widgets that are not visible. The practical effect: a StreamProvider on a background screen no longer triggers pointless rebuilds.

📚 Sources and documentation