Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions handling-writes/custom-conflict-resolution.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
description: "Implement custom conflict resolution in PowerSync for concurrent updates from multiple offline clients."
---

The default behavior is "**last write wins per field**". Updates to different fields on the same record don't conflict with each other. The server processes operations in the order received, so if two users modify the *same* field, the last update to reach the server wins.

For most apps, this works fine. But some scenarios demand more complex conflict resolution strategies.
See [Handling Update Conflicts](/handling-writes/handling-update-conflicts) for basic guidance on how to handle conflicts. For most apps, the approaches documented there are fine. But some scenarios demand more complex conflict resolution strategies.

## When You Might Need Custom Conflict Resolution

Expand Down Expand Up @@ -481,7 +479,7 @@

## Strategy 5: Server-Side Conflict Recording

Sometimes you can’t automatically fix a conflict. Both versions might be valid, and you need a human to choose. In those cases you record the conflict instead of picking a winner. You save both versions in a write_conflicts table and sync that back to the client so the user can decide.

Check warning on line 482 in handling-writes/custom-conflict-resolution.mdx

View check run for this annotation

Mintlify / Mintlify Validation (powersync) - vale-spellcheck

handling-writes/custom-conflict-resolution.mdx#L482

Did you really mean 'write_conflicts'?

The flow is simple: detect the conflict, store the client and server versions, surface it in the UI, and let the user choose or merge. After they resolve it, you mark the conflict as handled.

Expand Down
8 changes: 5 additions & 3 deletions handling-writes/handling-update-conflicts.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
---
title: "Handling Update Conflicts"
description: "Understand how PowerSync resolves conflicts when multiple users update the same records while offline."
description: "Understand what happens when multiple users update the same records while offline."
---

**The default behavior is essentially "last write wins", but this can be** [**customized by the developer**](/handling-writes/custom-conflict-resolution)**.**
By design PowerSync is unopinionated when it comes to handling conflicts on the backend. On the client, mutations are stored in an "upload queue" - an ordered log of mutations. This upload queue must be sequentially drained against backend API endpoints configured by the developer. The developer's app backend therefore dictates how mutations from clients are processed and applied against the source database. PowerSync then replicates and syncs those mutations back to the client. This is known as server-authoritative reconcilliation.

Check warning on line 6 in handling-writes/handling-update-conflicts.mdx

View check run for this annotation

Mintlify / Mintlify Validation (powersync) - vale-spellcheck

handling-writes/handling-update-conflicts.mdx#L6

Did you really mean 'unopinionated'?

Check warning on line 6 in handling-writes/handling-update-conflicts.mdx

View check run for this annotation

Mintlify / Mintlify Validation (powersync) - vale-spellcheck

handling-writes/handling-update-conflicts.mdx#L6

Did you really mean 'reconcilliation'?
Comment thread
kobiebotha marked this conversation as resolved.

In the simplest backend implementation, the behavior of the overall system will be per-field Last-Write-Wins (LWW). However, this can be [customized](/handling-writes/custom-conflict-resolution).

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

Expand All @@ -17,7 +19,7 @@

* 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.
A conflict may arise when two clients update the same field on 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:

Expand Down