Docs

Offline-first apps

Keep reading, querying, listening and writing documents with no connection; everything syncs in order when it comes back.

Updated Oct 17, 2026Open in console

Turn on offline mode once and documents keep working without a network: reads and queries answer from a local cache, live listeners keep firing, and writes are applied locally at once and queued. When the connection returns, the queue is sent in the original order. It works in browsers, React Native and Node.

import { SovariaSDK, indexedDbStorage } from '@sovaria/sdk'

const sov = new SovariaSDK({ projectUrl: 'https://<ref>.sovaria.in', anonKey: '<anon key>' })
const offline = sov.enableOffline({
  storage: indexedDbStorage(),                                 // survives reloads
  onSyncError: (error, writes) => console.warn('refused by the server', error, writes),
})

await sov.collection('todos').add({ title: 'works on a plane', done: false })   // instant, even offline
const stop = await sov.collection('todos').where('done', '==', false).onSnapshot((snap) => {
  render(snap.docs.map((d) => ({ ...d.data, saving: d.hasPendingWrites })))
})
await offline.pendingWrites()   // what still has to reach the server

How it behaves

OnlineOffline
Read a documentFrom the server; the cache is refreshedFrom the cache (fromCache); a document never read before fails with NETWORK_ERROR
Query and countFrom the server; results are cachedRun on the cached documents of the collection with the same operators, ordering, cursors and limits
Live listenersPushed changesKeep firing from the cache, including your own offline writes (hasPendingWrites); a listener started offline answers from the cache
Writes and batchesCommitted at onceApplied to the cache at once (field transforms too: increment, arrayUnion, serverTimestamp…) and queued
TransactionsRun on the serverFail with NETWORK_ERROR: their reads must be current, as in Firebase
  • When the connection is back (the browser's online event, the next successful request, or every 30 seconds) the queue is sent one commit at a time, oldest first, so the server sees the writes in the order you made them.
  • A queued write the server refuses — a collection rule, a row policy, a version precondition — is dropped, reported to onSyncError, and the cache is put back to the server's version of those documents.
  • Access rules still apply: nothing in the queue skips them, and the cache only holds documents this user was allowed to read.
  • Call offline.clear() when a user signs out, so the next user of the device doesn't see their cache or queue.

Where the cache lives

StorageUse it for
indexedDbStorage()Browsers: survives reloads and restarts.
keyValueStorage(AsyncStorage)React Native, or any store with getItem / setItem / removeItem / getAllKeys.
memoryStorage()The default: tests, servers, or a cache that ends with the page.
Something unclear or missing on this page?Tell us