The optimistic client’s persistLocal option stores eligible local tables in
IndexedDB. It restores them during startup and shares updates between tabs with
the same origin and storage identity.
This guide continues Local-only tables. It persists local tables such as drafts. It does not persist the synced dataset or make server queries available offline.
Enable storage
Add persistLocal to that guide’s src/rindle-client.ts configuration:
export const app = await createRindleClient({
schema: clientSchema,
mutators,
user: currentUser,
api: { url: "", headers: () => ({ "x-user": currentUser() }) },
persistLocal: {
user: currentUser(),
onError: (error) => console.error("Local persistence failed", error),
},
onRejected: (envelope, reason) => window.alert(`${envelope.name}: ${reason}`),
});
The imports and development identity come from the preceding guide. With storage
available, createRindleClient waits for the initial restore before it returns.
Your first local query can therefore read restored drafts.
All { local: true } tables participate. Tables declared with
{ local: "session" } remain ephemeral and per-tab.
Use a stable storage identity
persistLocal.user selects one IndexedDB database per origin and user string.
It stays fixed for that client’s lifetime. It is separate from the authenticated
principal that authorizes server reads and mutations.
Close and recreate the client when the signed-in user changes. Choose anonymous storage deliberately: all clients using the same anonymous identity share its local data on that origin.
Understand the durability boundary
A local write updates the engine before asynchronous storage completes. Awaiting
store.writeLocal does not acknowledge a durable disk write. A crash can lose a
recent update, and the browser can evict storage.
The persistence layer uses IndexedDB, BroadcastChannel, and Web Locks to coordinate
tabs. One tab sequences durable writes; other tabs forward and mirror updates.
Storage failures can report through onError. Missing browser APIs can instead
produce console warnings and disable persistence or cross-tab coordination.
Local writes can continue without durable storage.
requestPersistentStorage: true also requests the browser’s persistent-storage
permission. The browser controls whether it grants the request; this option does
not turn local drafts into a server backup.
A changed local schema hash resets the stored local dataset. There is no application migration callback in this option. Plan an explicit export or other migration path if local data must survive schema changes.
Clear data on logout
Closing a client does not delete its stored rows. If your logout policy requires removal, close the client and then delete its local database:
import { deleteLocalPersistence } from "@rindle/optimistic";
import { app } from "./rindle-client.ts";
export async function clearLocalData(storageUser: string) {
app.close();
await deleteLocalPersistence(storageUser);
}
Pass the same string used for persistLocal.user. Coordinate logout across your
application’s tabs so another live client does not continue using that identity.