Build1 distinct publisher3 min readPublished
Shivkrishna Shah's React Native sync pattern puts the write queue inside the database instead of beside it. What it leaves unstated is what decides whether replay is safe.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The hole in the design as published is the middle state. `syncStatus` takes one of four values [5], and the queue is defined as a live query over two of them, pending and failed [9]. A record that the engine flipped to syncing, on a handset that then lost power or got force-quit, belongs to neither set. Because `syncStatus` is durable data rather than app state [7], it stays syncing through the relaunch, and nothing in the described queue will look at it again. Anyone building this needs a reclaim pass at startup that ages syncing rows back to pending [15], which is another way of saying the queue is at-least-once and some writes will reach the server twice.
So the server contract matters more than the client code. Shah names duplicates as one of the two bugs that will bite [11], and his schema already holds the fix: `serverId` stays null until the server acknowledges the row [5], so the device-minted UUID in `localId` [6] is the only identifier that survives a retry [16]. Replay is safe only if the API deduplicates on that UUID and returns the same `serverId` for a repeat submission rather than inserting a second row. The text supplied stops before saying whether it does [17]. That is the clause to insist on, because it separates a sync engine from a duplicate generator.
The conflict input is `updatedAt`, read from the device clock [5]. Across a field fleet that is the least trustworthy column in the row, and the handset most likely to be carrying a stale clock is the one that spent the day offline in a warehouse, which is also the one whose timestamp decides the merge. Last-write-wins on device time is a defensible policy. It is not a default you get to leave unwritten, because someone will eventually ask which of two visit logs survived and why.
The reason to spend this much on plumbing is the failure mode Shah describes: field users who stop trusting the app go back to paper and WhatsApp [13]. Paper has excellent offline availability. So does a group chat, and neither one reports into your database.
Weigh the evidence for what it is. One practitioner, one post, a React Native platform he says field teams in several countries use daily [2], with no duplicate rate and no count of rows sitting in failed. The examples are Realm and NetInfo, with a claim that the shape ports to WatermelonDB, SQLite or MMKV-backed queues [12]. What you can check without trusting the anecdote is structural: six extra columns on every offline-writable table [14], and a queue that is a query over those columns instead of a second table [9], so it cannot drift out of step with the rows it describes. The price of the pattern is those columns plus one enforced save path [10]. The price of skipping it is a no-internet screen that field teams route around.
Ranked by verification strength, evidence, and original report placement.
Shah says he spent the last few years building and maintaining an offline-first React Native platform used daily by field teams across multiple countries.
Every save goes through one function that writes to Realm with syncStatus 'pending' and then calls requestSync('write') fire-and-forget; there is no await fetch, no try/catch around a network call and no online check, and the save is complete when the transaction commits.
The examples use Realm DB and NetInfo, and Shah says the pattern maps cleanly onto WatermelonDB, SQLite or MMKV-backed queues.
Shivkrishna Shah published "Offline-First in React Native: Building an Auto-Sync Engine That Users Never Think About" on dev.to.
In the pattern, the local database is the source of truth and the server is a replica that gets reconciled: every read comes from the local DB, every write goes to the local DB first, and the UI never talks to the network.
Every offline-writable schema carries the same sync metadata: localId (UUID generated on-device, used as primary key), serverId (nullable int assigned by the server after first sync), syncStatus ('pending' | 'syncing' | 'synced' | 'failed'), updatedAt (device clock, for conflict resolution), syncedAt (last successful server ack) and retryCount (exponential backoff counter).
Follow any of these and your For You feed starts watching them — no settings page required.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Illustrated pattern, no measurement
The post supplies concrete, internally consistent artefacts — a schema with six named sync fields, a single-save code path, a NetInfo listener, and a PENDING/SYNCING/SYNCED/FAILED lifecycle with a 2^retryCount x 30s backoff — which is real technical detail a reader can inspect. But it is one self-published practitioner account with no benchmarks, error rates, or third-party corroboration, and the body breaks off before the conflict-resolution rule and any server dedup contract, leaving the load-bearing correctness question undocumented.
Self-reported use only
The only adoption signal is the author's own statement that he built and maintains an offline-first React Native platform used daily by field teams across multiple countries, plus the fact that the pattern is expressed over widely used building blocks (Realm, SQLite, WatermelonDB, MMKV, NetInfo). There are no named deployments, user or record counts, downloads, or external references, so measured adoption stays near the floor.
Promises run ahead of the documented contract
Framing such as 'three things for free', zero-latency UX, airplane-mode parity and crash safety is stronger than what the text substantiates, and the piece promises to show how to avoid duplicates and conflicts while ending before either the conflict-resolution rule or a server deduplication contract appears. Two structural gaps push the same direction: records stranded in 'syncing' are outside the queue predicate, and localId is the only identifier available for replay. The overstatement is moderate rather than severe because the mechanics that are shown are specific and honestly caveated about NetInfo's limits.
Personal audience-building, vendor-neutral
The visible incentive is individual reputation and audience growth: a bylined post with personal handles on a developer platform, framed as the architecture the author wishes he had been handed on day one. There is no product for sale, no sponsorship, no funding or pricing event, and the technical framing is deliberately vendor-neutral (Realm and NetInfo as examples, with WatermelonDB, SQLite and MMKV named as equivalents). The main pull is toward presenting a personally maintained pattern as a general best practice.
Coherent but unverified and truncated
Confidence is limited by structure rather than by contradiction: one publisher, one self-reporting author, and a body that ends mid-argument. What is present is specific and internally consistent, and the derived gaps (queue predicate coverage, localId as sole idempotency key) follow directly from the quoted schema and query, so the descriptive claims are solid. Any judgement about whether the pattern is actually safe in production is not supportable from this material.
build
OpenClaw makes the channel the architecture, and the reasoning loop a lodger1 distinct publisher
build
The streaming edit is a software layer: proxies, stubs and an ffmpeg hook on storage you own1 distinct publisher
build
A 170-goal agent field test costs $0.49. Proving it actually passed costs more.1 distinct publisher
build
752 Nigerian institutions, shipped as a repo instead of an endpoint1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 26, 2026