fluttersmith/tipsGitHub ↗

Pass arguments to a Notifier through its constructor

IntermediateState management2 min read#riverpod#providers✓ Verified · Flutter 3.47.5 · 27 Sept 2026

A basket needs one quantity per product, and the method that changes it needs to know which product it is working on. In Riverpod 3 you give the notifier a constructor parameter and store it in a field:

quantity.dart✓ analyzed · tested
final quantityProvider =
    NotifierProvider.family<Quantity, int, String>(
      Quantity.new,
    );

class Quantity extends Notifier<int> {
  Quantity(this.sku);

  final String sku;

  @override
  int build() => 1;

  void increment() {
    final max = ref.read(stockApiProvider).inStock(sku);
    if (state < max) state++;
  }
}
  1. <Notifier, state, argument>
  2. the argument goes to the constructor
  3. every method can use the argument

NotifierProvider.family calls the function you give it with the argument. Quantity.new is a constructor tear-off, so the argument lands in sku. From then on, build and every method can read it without passing it around.

Callers pick the instance by calling the provider with an argument:

quantity.dart✓ analyzed · tested
void addOneLamp(WidgetRef ref) {
  ref.read(quantityProvider('lamp').notifier).increment();
}

What changed from Riverpod 2

Riverpod 2 had a separate FamilyNotifier class. The argument came in through build(String sku) and methods read it back from a getter called arg. That class is gone:

family_notifier.dart✓ analyzed · tested
class OldQuantity extends FamilyNotifier<int, String> {
  @override
  int build(String sku) => 1;

  void increment() {
    // `arg` held the argument.
    if (arg.isNotEmpty) state++;
  }
}

To migrate, extend Notifier, move the build parameter into the constructor, and rename arg to your field. The same goes for AsyncNotifier and StreamNotifier. There are no family variants of those either.

Good to know

  • One instance per argument. quantityProvider('lamp') returns the same notifier every time you call it with 'lamp', and 'rug' gets its own.
  • Arguments are compared with ==. Strings, numbers, enums and records work out of the box. For your own classes, implement == and hashCode, or every call creates a new provider.
  • Need more than one argument? Pass a record, such as (shop: 'north', sku: 'lamp'). Records already have value equality.
  • Add .autoDispose (or isAutoDispose: true) if the per-argument state should go away when no screen shows that product.

Adapted from tip #97 in Flutter Tips & Tricks by Andrea Bizzotto (MIT). Updated for current Flutter. Not affiliated with or endorsed by the original author. Suggest an edit.