Realm Client Reset: Deciding Between Recover and Discard Local Changes
A decision guide to Realm client reset handlers: when to recover unsynced changes, when to discard local data, and how to validate the choice before it fires in production.
07 Aug 2026, 12:10 UTC

What a client reset actually forces you to decide
In Atlas Device Sync (the sync service formerly branded MongoDB Realm), a client reset happens when the server can no longer reconcile a device's local history with the authoritative server state. The local realm file is replaced with a fresh copy of the server data. Common triggers include a change to the user's sync permissions, a server-side deletion of objects the device is tracking, or a change to the partition or schema the client subscribes to.
The engineering decision is narrow but consequential: when the reset fires, do you try to carry the device's not-yet-uploaded writes forward, or do you drop them and accept the server's version? Most SDKs expose this as a choice between a recover unsynced changes handler and a discard local changes handler.
Both replace the local file. The difference is what happens to writes that never reached the server.
Constraints that usually decide it before you compare features
- Who authored the unsynced writes. Field notes typed offline by a technician are expensive to recreate. Cached server data is not.
- Why the reset fired. A permission change means some local writes may now be illegal to upload. Recovery cannot make an unauthorized write authorized.
- Whether the app is offline-first. If devices routinely run disconnected for hours, discarding is a data-loss feature, not a safety feature.
- Device budget. A full re-download after discard is the cheapest path in CPU terms but the most expensive in network. Recovery adds a merge pass on top.
- Whether you already have an export path. If you write a local export before the reset, discard stops being irreversible.
Comparing the two handlers
| Dimension | Discard local changes | Recover unsynced changes |
|---|---|---|
| Local unsynced writes | Deleted with the old realm file | Staged, then re-applied to the new server snapshot |
| Server state after reset | Exactly the server's current state | Server state plus whatever local writes re-apply cleanly |
| Best fit | Server-authoritative or read-heavy apps | Offline-first apps with user-authored data |
| Main risk | Silent loss of work the user believed was saved | Repeated resets or dropped writes when local changes conflict with new permissions or schema |
| Relative cost | One full download | Full download plus a merge/re-apply pass |
Trade-offs worth arguing about
Discard is the honest default when the server owns the truth
If every local object is a projection of server data, recovery buys nothing and adds a failure mode. Discard also terminates the reset cleanly: there is no second pass that can fail, and no risk of a reset loop. The cost is that any write the user made while offline disappears without a trace unless you log it.
Recovery is worth it only if you can tolerate it failing
Recovery re-applies local writes onto the new snapshot. That works when the writes are still valid under the new server rules. It does not work when the reset was caused by a permission change that makes those writes unauthorized, or by a schema change that removes a field the local write depends on. In those cases the writes are dropped or the reset repeats. Treat recovery as best-effort, and design the UI so a user can tell that some work did not survive.
The shared failure mode: reset loops
Frequent resets are almost never a handler bug. Look for permissions or partition keys that flap, or a client that keeps writing objects the server immediately rejects. A loop is more damaging than a single discard because it burns bandwidth and battery on every reconnect.
A handler shape you can adapt
Handler names and signatures differ across SDKs and versions, so the block below is deliberately schematic. Confirm the exact API against your SDK's client reset documentation before copying it.
// Pseudocode. SDK-specific names differ - verify before use.
// Runs during Realm initialization, after the user is authenticated.
syncConfig = {
partitionValue: '<partition-key>',
clientResetHandler: {
// Fires before the local file is replaced.
onBeforeReset: () => {
// Last chance to export unsynced objects the user cares about.
exportUnsyncedToDisk(); // your own function
},
// Fires after the new server snapshot is in place.
onAfterReset: () => {
// Re-open the realm, then either re-apply staged writes
// (recover strategy) or surface a 'some local edits were not
// saved' notice (discard strategy).
reopenRealm();
}
}
}Two practical notes. First, keep the pre-reset step fast and dependency-free: it runs while the app is already in an error path. Second, if you choose recovery, log every write the merge drops. Silent drops are what turn a technical event into a support ticket.
Validating the choice before it happens in production
- Start the app, sign in, and let sync settle.
- Take the device offline and create several objects the user would care about losing.
- While still offline, trigger a server-side change that invalidates the local state - for example, change the user's permissions or the partition key in the App Services UI.
- Bring the device back online and let the client reset fire.
- Check the outcome: with discard, the offline objects should be gone and the realm should match the server; with recovery, the objects should reappear and then upload, or be explicitly reported as dropped.
Run this once per strategy on a throwaway app rather than a shared staging environment, because the permission change affects every client using that user.
Limitations and checks
- Client resets are exceptional events, not part of the normal sync loop. A handler that has never fired in testing is untested code.
- Recovery can raise peak memory and network use during the merge. Watch the device's resident set size on your lowest-spec target if you sync large realms.
- Reset frequency is the metric to monitor. If resets correlate with a deploy, suspect a permission or schema change rather than the handler.
- Exact handler names, the availability of the recovery strategy, and trigger behavior vary by SDK and by Device Sync version. Verify against current documentation for your platform.
Rollback
A client reset replaces the local realm file, so there is no undo once the handler runs. The only rollback is restoring from something you saved yourself: a system-level device backup, or an application export written before the local file is replaced. If losing local writes is unacceptable in your product, implement that export first and treat the handler choice as a secondary decision.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.