Building for Low Connectivity: Offline-First Applications for Nigerian Users
An application that requires continuous internet connectivity is not a Nigerian application — it is a feature that works occasionally. Building for intermittent connectivity is not a feature; it is a fundamental architecture decision that determines whether your software is actually usable in the contexts where your users actually work.
Building for Low Connectivity: Offline-First Applications for Nigerian Users
Internet connectivity in Nigeria is fundamentally different from the connectivity assumptions that underpin most software developed for the global market. A Lagos Island office with 50mbps fibre has genuine high-speed internet. A field sales representative driving from Ibadan to Oshogbo has intermittent 3G between towns, no signal in rural stretches, and a switching timeline that makes long-running requests unreliable. A distribution warehouse in Kano with a generator-dependent connection loses internet every time the generator is serviced.
A software application that assumes persistent internet connectivity works for the office. It does not work for the field — and in most Nigerian businesses, a significant portion of the users who matter most to the business are in the field.
The failure mode of connectivity-requiring software is not "works worse". It is "does not work at all". A delivery driver who cannot access the route assignment application when they are between network coverage areas is not navigating slowly — they are not navigating. A sales representative who cannot enter an order because the system is offline is not taking orders slowly — they are not taking orders.
Offline-first architecture shifts the assumption from "the network is available" to "the network may or may not be available, and the application must function regardless".
The Spectrum of Offline Capability
Offline-first is a spectrum, not a binary. The right point on the spectrum depends on the application's use case and the nature of the offline constraint.
Read-only offline access: The application stores a local copy of relevant data. In offline mode, users can view but not modify data. Suitable for reference applications — product catalogues, client directories, price lists, route maps. The simplest offline implementation.
Write-capable offline with queued sync: The application stores writes locally when offline and syncs them to the server when connectivity is restored. Users can complete transactions — enter orders, record deliveries, log activities — regardless of connectivity. The sync queue ensures nothing is lost. Requires conflict resolution logic for cases where the offline device's data conflicts with server state after reconnect.
Fully bidirectional offline with conflict resolution: Both local and server state can change during an offline period, and merging these changes on reconnect requires explicit conflict resolution logic. Harder to build correctly. Required for collaborative applications where multiple users may modify the same records.
Core Technologies
Service Workers and the Cache API
A service worker is a JavaScript file that runs in the background independently of the page, intercepts network requests, and can respond from a local cache instead of the network. Service workers enable:
Precaching static assets: The application's HTML, CSS, JavaScript, and images are cached on first install. Subsequent loads use the cache, with the network request running in the background to update the cache. The application starts even when offline.
Runtime caching of API responses: When the service worker intercepts an API request, it checks the cache. If a cached response exists, it returns the cached response immediately while fetching an update from the network (stale-while-revalidate strategy). For read-heavy data that changes infrequently, this provides instant load times and offline capability simultaneously.
Background sync: Writes queued during offline periods are replayed against the network endpoint when connectivity is restored. The Background Sync API (supported in Chrome-based browsers and Android WebViews) handles this; for unsupported environments, a manual queue with retry logic is needed.
IndexedDB
IndexedDB is the browser's native transactional database — a structured data store available even when the application is offline. Unlike localStorage (which is limited to string key-value pairs and 5–10MB), IndexedDB can store complex JavaScript objects, large datasets, and binary data.
For offline-first applications, IndexedDB is the local database:
- Orders entered offline are written to IndexedDB with a status of "pending sync"
- The sync queue reads "pending sync" records and attempts to write them to the server
- On successful sync, the status is updated to "synced" and the record ID from the server is stored locally
Libraries that reduce IndexedDB complexity: Working with the raw IndexedDB API is verbose and callback-heavy. The Dexie.js library provides a clean promise-based API over IndexedDB with query support that resembles SQL. For React Native applications, WatermelonDB provides a reactive offline-capable database with built-in sync support.
TypeScript/JavaScript Sync Libraries
RxDB, WatermelonDB, and PouchDB (with CouchDB sync) are established libraries for offline-first applications with sync:
PouchDB + CouchDB: PouchDB is a client-side JavaScript database that replicates to CouchDB (or CouchDB-compatible services like IBM Cloudant). Replication is the sync mechanism — PouchDB handles the offline queue and CouchDB handles conflict resolution. The conflict resolution model is multi-master: both sides' changes are retained, and your application code selects which version to keep.
WatermelonDB: Designed for React Native and React. High-performance local database with a lazy-loading architecture (only loads records into memory when accessed). Sync protocol is designed to be implemented on the server side, giving control over conflict resolution logic.
RxDB: Offline-first reactive database based on RxJS. Works in browser, React Native, and Node.js. Multiple backend sync adapters.
Sync Conflict Resolution
When a user makes changes offline and another user (or process) modifies the same records on the server during the offline period, you have a conflict. Conflict resolution strategy depends on the data type:
Last-write-wins: The most recent write (by timestamp) is taken as authoritative. Simple to implement. Correct for most user-generated content that doesn't have concurrent editing (notes, comments, settings). Incorrect for financial records where both operations should be applied (inventory decrements from two different warehouse transactions that both happened offline).
Operational transformation: Each offline operation (increment inventory by 5, change price to ₦12,500, add line item to order) is recorded as an operation rather than a state snapshot. Operations are replayed in deterministic order on the server. Correct for financial and inventory records. More complex to implement.
Field-level merge: Last-write-wins at the field level rather than the record level. If two offline clients both modify the same record but different fields, merge both changes. If they modified the same field, flag for user review. Balanced approach for many business data types.
User review queue: When automatic resolution is not confident, queue the conflict for user review — present the two versions and ask the user to choose or merge. Appropriate for records where the financial or customer relationship stakes are high enough that automated resolution is unacceptable.
Practical Implementation Decisions
Scope the offline data carefully: You do not need to cache the entire database client-side. Identify which data the user needs in offline mode — their open orders, their assigned deliveries, the product catalogue they need for order entry — and sync only that subset. Syncing 50,000 product records to a field sales device for a sales rep who covers 200 SKUs is unnecessary and increases the sync time.
Optimistic UI updates: When a user submits an action, update the UI immediately (optimistic update) rather than waiting for server confirmation. Write to the local queue, update the view, and trust that the sync will succeed. If the sync fails permanently, roll back and notify. Users experience instant responses regardless of network state.
Connectivity detection: The browser's navigator.onLine property is unreliable in environments with captive portals or very low-bandwidth connections where onLine returns true but requests time out. A more reliable approach: attempt a small HTTP request to a known fast endpoint (your own API or a public CDN) and measure response time. If it fails or exceeds 5–10 seconds, treat as offline.
Sync status visibility: Users in field contexts need to know whether their actions have synced. A visible sync status indicator — "Last synced: 14 minutes ago" or "4 items pending sync" — prevents uncertainty about whether data has been saved. The indicator that says "3 items awaiting sync" is more useful than an error after the fact.
Conflict UX: When a sync conflict requiring user resolution occurs, surface it in a way that allows resolution without interrupting the user's current workflow. A notification with deferred review — "Review 2 sync conflicts when convenient" — is less disruptive than a modal that blocks operation.
Testing Offline Behaviour
Offline behaviour must be tested explicitly — it is not surfaced by standard browser testing:
- Chrome DevTools Network tab > "Offline" mode tests the offline state
- Simulate slow connections (Slow 3G preset in DevTools) to test partial connectivity
- Test sync queue persistence across browser tab closes and restarts
- Test conflict scenarios by submitting contradictory offline queue items
- Test the boundary condition where some queued items succeed and later items fail — the sync resumption logic must handle partial progress correctly
Offline-first in the Nigerian context is not an edge case feature — it is a baseline requirement for application quality in field use. Building it correctly requires deliberate architecture from the start; retrofitting offline capability onto a connectivity-assuming architecture is significantly more expensive than building it in.
Related Articles
- Progressive Web Apps for Nigerian Businesses — Building web experiences that work like native apps
- Database Choices for Nigerian Business Applications — Selecting the right database including offline-capable options
- USSD Is Not Dead: Inclusive Applications for Every Nigerian Phone — Building for the full spectrum of Nigerian connectivity