Offline Support

Koolbase database works offline out of the box. Reads load instantly from local cache, writes are queued and synced automatically when the network is restored.

How it works

The SDK uses a local Drift database on the device to cache query results and queue writes. No configuration needed — offline support is enabled automatically when you initialize the SDK.

ReadsCache-first — returns local data instantly, then refreshes from network in the background
WritesOptimistic — saves locally first, syncs to server when online
Auto-syncTriggered automatically when network connectivity is restored
Manual syncCall syncPendingWrites() at any point to force a sync

Cache-first reads

Every query automatically checks local cache first. If data exists, it returns immediately and triggers a background network refresh. Use isFromCache to know the data source.

lib/posts_screen.dartDart
final result = await Koolbase.db
  .collection('posts')
  .get();

if (result.isFromCache) {
  // Data loaded from local storage — network refresh in progress
  print('Showing cached data');
} else {
  // Fresh data from server
  print('Showing live data');
}

for (final post in result.records) {
  print(post.data['title']);
}

Background refresh stream

Listen to the collection stream to receive updates when the background network refresh completes:
lib/posts_screen.dartDart
@override
void initState() {
  super.initState();

  // Listen for fresh data after background refresh
  Koolbase.db.collection('posts').stream.listen((result) {
    setState(() => _posts = result.records);
  });
}

Offline writes

Inserts work the same way whether you're online or offline. If the network is unavailable, the write is queued locally and synced automatically when connectivity is restored.

lib/posts_screen.dartDart
// Works online and offline — no change to your code
final post = await Koolbase.db.insert(
  collection: 'posts',
  data: {
    'title': 'Written offline',
    'body': 'This will sync when back online',
  },
);

// If offline, returns an optimistic record immediately
print(post.id); // temporary local ID until synced

Optimistic updates

When offline, the SDK generates a temporary local ID for the new record. Once synced, the server assigns a permanent ID. Design your UI to handle this gracefully — for example, avoid relying on the ID for navigation until after sync.

Syncing pending writes

The SDK auto-syncs when network connectivity is restored. You can also trigger a sync manually at any point — for example, on app resume or after a user action.

lib/main.dartDart
// Manual sync — call at any point
await Koolbase.db.syncPendingWrites();
lib/main.dartDart
// Sync on app resume
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
  if (state == AppLifecycleState.resumed) {
    Koolbase.db.syncPendingWrites();
  }
}

Retry behavior

Failed writes are retried automatically. After 3 failed attempts, the write is dropped and logged. This prevents the queue from growing indefinitely on persistent errors.

Max retries3
On failureSkip and continue — other writes are not blocked
After max retriesWrite is dropped and logged
Retry triggerEvery sync attempt (auto or manual)

Local storage

Offline data is stored in a local SQLite database using Drift. The database persists across app restarts and is stored in the app's private storage directory — not accessible to other apps.

Storage engineDrift (SQLite)
Cache scopePer user — no cross-user data leakage
PersistenceSurvives app restarts
Cache invalidationAutomatic after successful write or sync

Current limitations

Conflict resolution

Not supported — last write wins. Multi-device conflicts are not resolved.

Offline updates/deletes

Only inserts are queued offline. Updates and deletes require network.

Realtime offline

WebSocket subscriptions require network. Offline reads use cached data only.

Nested populate offline

Populate queries use network data only — not resolved from local cache.