The default behavior is essentially “last write wins”, but this can be customized by the developer.

The change queue on the client stores three types of operations:

  1. PUT / Create new row — contains the value for each non-null column
  2. PATCH / Update existing row — contains the ID, and value of each changed column
  3. DELETE / Delete existing row — contains the ID

It is up to your app backend to implement these operations and associated conflict handling.

The operations must be idempotent — i.e. the backend may receive the same operation multiple times in some scenarios, and must handle that appropriately.

  • A per-client incrementing operation ID is included with each operation that can be used to deduplicate operations, and/or the backend can implement the operations in an idempotent way (e.g. ignore DELETE on a row that is already deleted).

A conflict may arise when two clients update the same record before seeing the other client’s update, or one client deletes the record while the other updates it.

Typically, the backend should be implemented to handle writes as follows:

  1. Deletes always win: If one client deletes a row, any future updates to that row are ignored. The row may be created again with the same ID.
  2. For multiple concurrent updates, the last update (as received by the server) to each individual field wins.
    1. If you require different behavior to “last write wins”, implement custom conflict resolution.

The server could implement some validations. For example, the server could have a record of orders, and once an order is marked as “completed”, reject any further updates to the order.

Future versions may include support for custom operations, e.g. “increment column by 1”.

Using CRDTs to Merge Updates Automatically

CRDT data structures such as Yjs can be stored and synced using PowerSync, allowing you to build collaborative apps that merge users’ updates automatically.

See the CRDTs section for more detail.

Built-in support for CRDT operations in PowerSync may also be added in the future.