Skip to content

Riverpod Query Metadata

Metadata allows you to attach extra information to your queries and mutations. This is extremely powerful when combined with global observers to handle side effects like showing snackbars, logging, or triggering analytics consistently across your entire app.

Both queryProvider and mutationProvider accept a meta property within their options.

Use QueryMeta to store info about a data fetch:

final usersProvider = queryProvider<List<User>>(
'users'.toQueryKey(),
() => api.fetchUsers(),
options: QueryOptions(
meta: const QueryMeta(
errorMessage: 'Failed to load users. Please check your connection.',
),
),
);

Use MutationMeta to store info about an update:

final createUserProvider = mutationProvider<User, String>(
(name) => api.createUser(name),
options: MutationOptions(
meta: const MutationMeta(
successMessage: 'User created successfully!',
errorMessage: 'Could not create user.',
invalidateKeys: [['users']],
),
),
);

The real power of metadata comes from consuming it in a global observer. This allows you to write the logic for showing snackbars or alerts once and have it work for every query/mutation in your app.

class FeedbackObserver extends FasqObserver {
@override
void onMutationSuccess(MutationSnapshot snapshot, MutationMeta? meta, BuildContext? context) {
if (meta?.successMessage != null && context != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(meta!.successMessage!)),
);
}
}
@override
void onQueryError(QuerySnapshot snapshot, QueryMeta? meta, BuildContext? context) {
if (meta?.errorMessage != null && context != null) {
showGlobalErrorDialog(context, meta!.errorMessage!);
}
}
}

Override the fasqObserversProvider at the root of your app:

void main() {
runApp(
ProviderScope(
overrides: [
fasqObserversProvider.overrideWithValue([
FeedbackObserver(),
FasqLogger(),
]),
],
child: const MyApp(),
),
);
}
  1. Separation of Concerns: Your UI widgets don’t need to know about snackbars or error dialogs. They just watch the provider.
  2. Consistency: All error messages and success alerts look and behave the same way throughout the app.
  3. Declarative: Side effects are declared alongside the provider definition, making the intent clear.