Skip to main content
SyncProvider is the bridge between your SyncStore instance and the React component tree. It calls store.hydrate() on mount, optionally flushes pending mutations after hydration, and makes the store available to all CL Sync hooks via React context.

Basic setup

Props

SyncStore
required
The SyncStore instance created by createSyncStore. Provide the same instance on every render — changing this prop tears down and re-initializes the entire sync context.
MutationDefinition[]
An optional array of mutation definitions to register before hydration. Registering mutations here ensures that outbox items from a previous session are matched to their definitions and can be replayed when flushOnHydrate is true.
boolean
When true, SyncProvider calls store.flushPendingMutations() immediately after store.hydrate() resolves. Defaults to false. Use this when you want the simplest possible setup and your auth token is already available at mount time.
ReactNode
required
The component subtree that will have access to sync context.

Mounting behavior

On mount, SyncProvider runs the following sequence:
  1. Calls store.registerMutations(mutations) if mutations was provided.
  2. Calls await store.hydrate() to load IndexedDB and run any pending migrations. hydrate() sets status.hydrated = true and notifies all subscribers when it completes.
  3. If flushOnHydrate is true, calls await store.flushPendingMutations() after hydration resolves.
All children render immediately — they see status.hydrated === false on the first render, then re-render once hydration completes. Use useSyncStatus() to gate content on hydration:

Manual flush control

If you need to refresh an auth token or perform async work before replaying mutations, skip flushOnHydrate and handle the sequence yourself:
Calling store.hydrate() more than once is safe — subsequent calls are no-ops if the store is already hydrated.

Scoping the provider to a user

Create the store inside a component (or with useMemo) that re-creates it when the authenticated user changes. This ensures each user gets a fresh scope:
Do not create the store inside a component without useMemo. A new store on every render loses all cached state and re-hydrates from scratch.