Comparison
Qora, flutter_query, and cached_query are server-state libraries built for data that resides on a remote server. Provider and BLoC target client state; comparing them to Qora conflates two distinct problem domains.
This page documents the meaningful differences between the three server-state solutions. Claims about other libraries are based on their public documentation as of November 2026; open an issue if something is out of date.
Selection Criteria
| If you need... | Best fit |
|---|---|
| A solid SWR cache with minimal setup | Any of the three |
| Writes made offline, queued and replayed on reconnect | Qora |
Queries that pause offline and say so (FetchStatus.paused) | Qora |
| Per-query network mode (online / always / offlineFirst) | Qora |
| Thundering-herd control on reconnect | Qora |
| Tag-based invalidation | Qora |
| Disk persistence with a ready-made adapter | cached_query (cached_storage) |
| Disk persistence on your own storage backend | Qora or cached_query |
| A hooks-only API, closest to TanStack Query on the web | flutter_query |
| Hooks or widget builders, your choice | Qora |
| Pure Dart core usable outside Flutter | Qora or cached_query |
| A tab in Flutter DevTools today | cached_query |
| An in-app debug overlay | Qora |
Qora Differentiators
Offline Architecture
Offline behaviour in Qora is a set of cooperating pieces rather than a single refetch-on-reconnect flag:
NetworkModeper query: declare whether a query runsonlineonly,always(local DB), orofflineFirst(serve cache, refresh in background when online).- Offline mutation queue: writes submitted while offline return an optimistic result, are queued in order and replayed on reconnect. The queue is held in memory: it survives connectivity changes, not an app restart.
FetchStatus: a second-axis enum (fetching / paused / idle) emitted independently ofQoraState, allowing the UI to distinguish "no network" from "loading".ReconnectStrategy: limits the thundering herd on reconnect with a maximum number of concurrent refetches and random jitter between batches.
QoraBuilder<User>(
queryKey: ['users', userId],
fetcher: () => api.getUser(userId),
options: const QoraOptions(networkMode: NetworkMode.offlineFirst),
builder: (context, state, fetchStatus) {
if (fetchStatus == FetchStatus.paused) {
return OfflineBanner(staleData: state.dataOrNull);
}
return switch (state) {
Success(:final data) => UserCard(data),
Loading() => const CircularProgressIndicator(),
Failure(:final error) => ErrorWidget('$error'),
Initial() => const SizedBox.shrink(),
};
},
)
DevTools
Qora's in-app overlay (qora_devtools_overlay) runs inside your app in debug builds and shows every query with its state, data and staleness, plus the mutation queue. A Flutter DevTools extension sharing the same event protocol is in development; the version on pub.dev is not compatible with Qora 1.x yet.
Pure Dart Core
The qora package carries no Flutter dependency. It operates in CLI applications, Dart server-side code, and test suites without pulling in the Flutter SDK. qora_flutter is a thin opt-in widget binding layer on top.
Advanced Invalidation
invalidateQueries({required QueryFilter filter}) invalidates by state, last-used options, or any combination, not just by key prefix:
// Invalidate all online-mode queries that have not yet succeeded
client.invalidateQueries(
filter: (key, state, opts) =>
opts?.networkMode == NetworkMode.online && state is! Success,
);
cached_query: Ready-Made Persistence
cached_query ships cached_storage, a sqflite-based storage implementation maintained alongside the library, and a Flutter DevTools extension. Qora's PersistQoraClient covers the same use case through a StorageAdapter interface with an in-memory implementation included; adapters for specific backends (Hive, Isar, SharedPreferences) are implemented in your app for now.
Complementarity with BLoC and Riverpod
Qora, BLoC, and Riverpod address different concerns and are designed to be used together:
| Layer | Appropriate tool |
|---|---|
| Data that lives on a server (queries, mutations, pagination) | Qora |
| Complex UI state machines (checkout flows, multi-step forms) | BLoC |
| Client state and DI (theme, auth session, service graph) | Riverpod or Provider |
A production application commonly uses all three in combination. Refer to the integration guides when adding Qora to an existing BLoC or Riverpod codebase.
Related
Quick Start
Build a list and a detail screen backed by Qora, watch the cache work, then take the app offline.
Coming from TanStack Query
A precise mapping of TanStack Query concepts, hooks, and configuration options to their Qora equivalents. Covers what is identical, what is renamed, and what works differently.