reducer applies the change optimistically so your UI responds instantly.
Mutation lifecycle
When you callstore.enqueueMutation(definition, args), CL Sync runs these steps in order:
- Reducer — applies an immediate, synchronous optimistic change to the local cache.
- Outbox write — serializes
argsto IndexedDB so the mutation survives a reload. - Flush — calls your async
flushfunction to send the mutation to the server. - Ack or reject — on success, calls
onAck; on failure, callsonRejectand marks the item"failed"in the outbox.
Defining a mutation
Mutation options
string
required
A unique identifier for this mutation. Used as the
mutation field in OutboxItem. Must be stable across deployments so outbox items can be matched to their definitions on replay.(store: SyncStore, args: TArgs, clientMutationId: string) => void
Runs synchronously and immediately when
enqueueMutation is called. Apply your optimistic state change here. This function should be fast and side-effect-free beyond writing to the store.(args: TArgs, clientMutationId: string) => Promise<TResult>
Async function that sends the mutation to your server. If it throws, the outbox item is marked
"failed". The same clientMutationId is used on retries, enabling server-side deduplication.(store: SyncStore, args: TArgs, result: TResult, clientMutationId: string) => void
Called after
flush resolves successfully. Use it to apply server-authoritative data that differs from your optimistic update — for example, a server-generated timestamp or computed field.(store: SyncStore, args: TArgs, error: unknown, clientMutationId: string) => void
Called when
flush throws. Implement rollback logic here. CL Sync does not automatically revert optimistic changes — you are in full control of conflict resolution.Enqueuing mutations
Callstore.enqueueMutation directly or use the useSyncMutation hook in React:
clientMutationId as the third argument to enqueueMutation if you need to coordinate IDs across systems. If omitted, CL Sync generates one automatically.
Outbox and durability
Mutations persist in IndexedDB until they are either flushed successfully or explicitly removed. Each outbox entry carries full replay metadata:Flush options
flushPendingMutations accepts an options object to control which items are processed:
Deduplication with clientMutationId
CL Sync generates a stable clientMutationId for each outbox entry and passes it to both flush and onAck. The same ID is reused on every retry. Include it in your request body and deduplicate on the server using this ID: