# Local-First Database Conflict Resolution UI (Mobile)

> By Lawrence Arya, Founder & CEO of VP0. Published 2026-05-30, updated 2026-06-02. 4 min read.
> Source: https://vp0.com/blogs/local-first-database-conflict-resolution-ui-mobile

Most conflicts should never reach the user; the few that do need a calm, honest screen.

**TL;DR.** Local-first apps store data on-device and sync in the background, so the hard part is conflicts. Resolve most automatically at the data layer (last-write-wins or CRDTs); for ambiguous cases, design a clear comparison screen from a free VP0 design with keep-mine, keep-theirs, and keep-both. Never silently drop an edit.

In a local-first app, data lives on the device and syncs in the background, so the app works offline and feels instant. The hard part is conflicts: when the same item is edited on two devices while offline, something has to reconcile them, and occasionally the user has to decide. The short answer is, resolve most conflicts automatically at the data layer and design a clear, rare conflict-resolution UI from a free VP0 design for the cases a human must settle. Most conflicts should never reach the user; the few that do need a calm, honest screen.

## Why conflicts are the core problem

Local-first is great for users (instant, offline) but it shifts complexity to sync. The canonical reference, Ink and Switch's [local-first software](https://www.inkandswitch.com/local-first/) essay, frames the goal as software that is both offline-capable and collaborative, which means merging concurrent edits. Most of that should be automatic, using strategies like last-write-wins or CRDTs at the data layer, so users never see a conflict. But some conflicts are genuinely ambiguous (two different edits to the same field) and need a human choice. Security matters here too, because synced data crosses the network and devices, and roughly [71%](https://cybernews.com/security/) of mobile apps were found to leak sensitive data.

## How to design the resolution UI

VP0 is a free iOS design library for AI builders. First, minimize what reaches the UI: choose a merge strategy at the data layer so most conflicts auto-resolve. For the rest, build a clear comparison screen from a VP0 design via Cursor or Claude Code: show both versions side by side (what is on this device vs the synced version), label which is which and when each changed, and offer "keep mine," "keep theirs," or "keep both." Never silently drop a user's edit. On iOS this often pairs with [SwiftData](https://developer.apple.com/documentation/swiftdata) or CloudKit for the store and sync; your UI is only the human-decision layer. For the data screen itself, see [SwiftData UI template](/blogs/swift-data-ui-template/).

## Conflict handling, by layer

Here is who should resolve what.

| Conflict type | Resolve where |
|---|---|
| Different fields edited | Auto-merge (data layer) |
| Same field, clear recency | Last-write-wins (data layer) |
| Same field, ambiguous | Ask the user (UI) |
| Deleted vs edited | Ask the user (UI) |
| Anything sensitive | Auto + careful handling |

## A worked example

Say a notes app syncs across two devices. The user edits a note's title on their phone and its body on their iPad while offline. Those are different fields, so the data layer merges them automatically and nothing reaches the UI. But if both devices edited the same title differently, show a VP0-designed conflict screen: "This note was changed on two devices," the two titles with timestamps, and clear "keep this one," "keep that one," or "keep both as copies." Make the choice obvious and reversible. For connecting the sync backend, see [how to connect an API to an AI-built iOS app](/blogs/how-to-connect-an-api-to-an-ai-built-ios-app/); for the live-preview workflow while building this, [21st.dev-style live preview for mobile app templates](/blogs/21st-dev-style-live-preview-for-mobile-app-templates/).

## Common mistakes

The most common mistake is silently picking a winner and discarding the user's edit, which destroys trust. The second is showing a conflict screen for things that could auto-merge, annoying users with decisions they should not have to make. The third is a confusing comparison that does not clearly label which version is which. The fourth is no "keep both" escape hatch for ambiguous cases. The fifth is ignoring the security of synced data, exactly the risk behind the 71% figure.

## Key takeaways

- Local-first feels instant and works offline, but conflicts are the core challenge.
- Auto-resolve most conflicts at the data layer (last-write-wins or CRDTs) so users rarely see one.
- For ambiguous conflicts, show a clear comparison UI with keep-mine, keep-theirs, and keep-both.
- Never silently drop an edit, and handle synced data carefully since around 71% of apps leak data.

## Frequently asked questions

How do I design conflict-resolution UI for a local-first app? Resolve most conflicts automatically at the data layer, and for the ambiguous ones build a clear comparison screen from a free VP0 design that shows both versions with timestamps and offers keep-mine, keep-theirs, or keep-both.

Should the user see every sync conflict? No. Most conflicts (edits to different fields, or a clear most-recent edit) should auto-merge at the data layer. Only genuinely ambiguous conflicts should reach the user.

What merge strategy should I use? Last-write-wins is simplest for clear recency; CRDTs handle concurrent edits more gracefully. Use the data layer (SwiftData, CloudKit, or a sync engine) for this and keep the UI for human decisions only.

What is the worst conflict-handling mistake? Silently discarding a user's edit. Always preserve both versions when in doubt and let the user choose, with a reversible "keep both" option.

## Frequently asked questions

### How do I design conflict-resolution UI for a local-first app?

Resolve most conflicts automatically at the data layer, and for the ambiguous ones build a clear comparison screen from a free VP0 design that shows both versions with timestamps and offers keep-mine, keep-theirs, or keep-both.

### Should the user see every sync conflict?

No. Most conflicts (edits to different fields, or a clear most-recent edit) should auto-merge at the data layer. Only genuinely ambiguous conflicts should reach the user.

### What merge strategy should I use?

Last-write-wins is simplest for clear recency; CRDTs handle concurrent edits more gracefully. Use the data layer (SwiftData, CloudKit, or a sync engine) for this and keep the UI for human decisions only.

### What is the worst conflict-handling mistake?

Silently discarding a user's edit. Always preserve both versions when in doubt and let the user choose, with a reversible keep-both option.

---
*Published on the [VP0 Journal](https://vp0.com/blogs). Free to read, index and cite with attribution.*
