Collaboration

Users, agents, and devices share one authoritative repository through a Lix server:

Use LixRay or host your own server. See storage adapters for storage options.

Connection reference

openLix() defaults server.mode to "remote", executing SQL on the server. Supply storage and server.mode: "partial_replica" to create a partial replica with on-demand sync. Remote mode rejects storage; partial-replica mode requires it. No "sync" alias or full "replica" mode is supported.

remotepartial_replica
Reads and writes executeOn the serverOn a local replica
Client storageNone; do not pass storageAn explicit durable adapter
Network round tripEvery operationBackground synchronization; uncached data may need a fetch
Successful writeAccepted by the serverCommitted locally; may not yet be on the server
Offline workNoCovered reads and writes with resident dependencies

Remote mode

Use server: { url: lixConnectionUrl } for SDK access with server-acknowledged writes. It creates no local repository or synchronized files.

Partial-replica mode

Use server: { url: lixConnectionUrl, mode: "partial_replica" } with FilesystemStorage for files on disk or OpfsStorage for a browser replica. Current data and new commits sync automatically; SQL fetches missing native inputs on demand.

await lix.execute(...) confirms a local commit, not server receipt. Uploads run in the background; no sync() call is needed.

Connection URL and authentication

Use the host's absolute HTTPS connection URL with path /lix/{uuid}, not its project page URL. HTTP is accepted only on loopback. Both modes accept headers and async credential refresh:

server: {
  url: lixConnectionUrl,
  headers: async () => ({
    Authorization: `Bearer ${await getAccessToken()}`,
  }),
}

Opening and reconnecting

A fresh partial replica loads bounded metadata before openLix() resolves. SQL hydrates missing native inputs on demand. Existing replicas can open locally and reconnect in the background, potentially starting behind the server.

Offline, covered reads and writes with resident dependencies work; operations requiring missing native inputs fail explicitly. Pending commits upload after reconnect.

Replica format upgrades

Existing full replicas require explicit conversion before opening with server.mode: "partial_replica". Normal opening never falls back to eager full bootstrap. Conversion preserves the source and pending work; unsupported pending changes require explicit recovery. See the migration guide for supported formats, conversion, retained-source recovery and cleanup.

Use the local recovery API after opening:

const sources = await lix.replicaRecoverySources();
for (const source of sources.filter((item) => item.recoveryRequired)) {
  const data = await lix.exportReplicaRecovery(source.id);
  // Save data locally, including its unresolved-content descriptions.
  const receipt = await lix.recoverReplica(source.id);
  // Review receipt.branchIds separately from the user's current branch.
}

Recovery restores the captured rows onto separate branches. It does not delete the source. A restoration receipt is not a server acknowledgement. See the migration guide for limits and cleanup.

Receive collaborative updates

Both remote clients and partial replicas can observe queries:

const files = lix.observe("SELECT path FROM lix_file ORDER BY path");

const initial = await files.next();
const update = await files.next();

Remote clients receive updated query results from the server. Partial replicas apply incoming commits locally, then update affected observations.

Share a branch to see collaborators' accepted changes; use separate branches for work requiring review.

Concurrent changes

The server orders accepted updates. When a partial replica uploads changes based on an older head, the server reconciles them through the same native row merge pipeline used by branch merges. Changes to different rows or columns are preserved. For overlapping values, the default is last write wins in server acceptance order. Client timestamps and change identifiers do not decide the winner. An explicit branch merge uses its incoming source as the default winner.

Registered schema/plugin merge hooks participate in that same pipeline and can return a merged row. Files parsed by plugins inherit row merging and serialize the resolved rows; opaque file content is atomic. Ordinary concurrent edits do not require user conflict resolution. Incompatible schema or plugin changes still require a supported migration.

Acknowledgments and background updates bring replicas to the authoritative result while preserving newer pending local edits. A retry of an already accepted upload retains its identity and cannot become a new winning write. Resident reads and writes remain local; they do not wait for server confirmation.

Historical reads hydrate immutable commit data on demand and cache it in the replica's storage. Repeating a cached read does not fetch that history again. For explicit transactions, prefetch uncached historical inputs before beginning the transaction; a transaction cannot change its captured snapshot to hydrate missing history.

Presence

Use a separate service for presence: cursors, selections, typing, online status, and avatars. Lix synchronizes repository data.

Closing

Call await lix.close() for cleanup. Remote mode closes the server session. A partial replica stops its background worker without waiting for network delivery. Durable pending commits resume uploading on the next open.

A partial replica has no public API to await server confirmation. Use remote mode when each successful write requires server acknowledgment.

Closing does not delete either repository. Use deleteLix() for explicit hosted deletion.