Mobile API Best Practices · Offline-First & Sync

Delta Sync Protocols

Sync only what changed: change tokens, tombstones and resync.

Full re-downloads don't scale. A delta sync endpoint returns changes since a sync token (a server-issued opaque cursor over a monotonic change log or per-row updated_seq). Deletions are sent as tombstones (keep them long enough for slow clients). If a token is too old (log compacted), respond with 410 Gone / resync_required so the client does a full snapshot. Scope changes to what the user may see — permission changes are also "changes".

Sync approaches

Criterion Full snapshot updated_at > T Change log / sequence token
Bytes per sync Everything Changed rows Changed rows
Deletes Implicit Need soft deletes Tombstones in log
Clock-skew safe Yes No (use server time, ties) Yes (monotonic seq)
Missed-update risk None Concurrent commits can be skipped None if seq assigned at commit
Server cost High Low Low (log storage)
GET /v1/sync?since=st_000123987&limit=500

200 OK
{
  "changes": [
    {"type": "task", "op": "upsert", "id": "01J9…", "version": 14, "data": {…}},
    {"type": "task", "op": "delete", "id": "01J8…", "version": 9}
  ],
  "next_token": "st_000124487",
  "has_more": true
}

# Token older than retention:
410 Gone   {"type": "https://api.example.com/problems/resync-required"}

Common pitfalls

  • Using client clocks for 'changed since'.
  • Purging tombstones before all clients have synced.
  • Ignoring permission revocations (client keeps data it should lose).

Key points

  • Opaque sync tokens over a monotonic sequence
  • Tombstones for deletes
  • 410 → full resync

Further reading: Apple: CKSyncEngine

Practice questions

Why is updated_at > last_sync_time risky for delta sync?

Answer

Clock skew and transactions that commit out of timestamp order can make changes invisible to a client that already advanced its timestamp; a commit-ordered sequence avoids that.

What should the server do when a client's sync token is older than the retained change log?

Answer

Return a resync-required signal (e.g. 410 Gone) so the client discards its token and downloads a fresh snapshot.

Open in the app to mark lessons complete, take notes and track your progress.