$ status available for new projects·replies within 24 hours

+91 97125 15105hello@kamleshnishad.comLinkedIn

Mobile19 Aug 2025 · 2 min read

Delta sync on a 2G connection

Cover image

The brief was a field-survey app for health workers in rural districts. Records are collected offline all day and synced in the evening, often over a 2G connection.

Why full sync failed

Our first version posted every record as one JSON payload. At 3,000 records that was 4.2 MB, and on a throttled connection the request timed out after 40 seconds with nothing saved.

Send only what changed

We kept a local change log and sent compact diffs in batches of 200, each batch acknowledged before the next. If the connection dropped, the queue resumed from the last acknowledged batch.

for (const batch of chunk(changes, 200)) {
  await retry(() => api.push(gzip(batch)));
  await log.ack(batch.lastId);
}

The same 3,000 records synced in about six seconds. We placed first, and the client later took the approach into production.

Why batching alone wasn't the fix

Smaller requests reduce the odds of a single timeout, but on a connection that drops mid-sync they just mean you fail at batch 14 instead of batch 1. The part that actually mattered was making each batch resumable: the device never resends a batch that was already acknowledged, so a dropped connection picks up exactly where it left off instead of starting the whole sync over.

Choosing a batch size

200 records was the right number for this payload, not a universal constant. Too large and you reintroduce the timeout risk you were trying to avoid; too small and the per-batch round-trip overhead starts to dominate on a high-latency connection. The only way to pick it honestly is to test against the worst connection your users actually have, not the one in your office.

Beyond surveys

Any offline-first mobile app — field data collection, inventory counts, delivery confirmations — benefits from the same shape: keep a local append-only change log instead of a mutable snapshot, sync diffs instead of full state, and treat every batch as safe to retry.

0 comments

Join the discussion

No comments yet — be the first.