Getting Started

Comparison

How Qora compares to flutter_query and cached_query, the other server-state libraries for Flutter.

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 setupAny of the three
Writes made offline, queued and replayed on reconnectQora
Queries that pause offline and say so (FetchStatus.paused)Qora
Per-query network mode (online / always / offlineFirst)Qora
Thundering-herd control on reconnectQora
Tag-based invalidationQora
Disk persistence with a ready-made adaptercached_query (cached_storage)
Disk persistence on your own storage backendQora or cached_query
A hooks-only API, closest to TanStack Query on the webflutter_query
Hooks or widget builders, your choiceQora
Pure Dart core usable outside FlutterQora or cached_query
A tab in Flutter DevTools todaycached_query
An in-app debug overlayQora

Qora Differentiators

Offline Architecture

Offline behaviour in Qora is a set of cooperating pieces rather than a single refetch-on-reconnect flag:

  • NetworkMode per query: declare whether a query runs online only, always (local DB), or offlineFirst (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 of QoraState, 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.
user_screen.dart
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:

main.dart
// 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:

LayerAppropriate 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.

Qora manages server state. BLoC and Riverpod manage client state. The two domains are complementary; each library operates within its intended scope.

Copyright © 2026