Building web applications for users in Ethiopia quickly disabuses you of the assumption that high-speed Internet is guaranteed. Cell towers drop during rainstorms, mobile data bundles expire without warning, and latencies regularly swing from 50ms to 2,000ms.
When I built Mezmur+, a platform for over 3,000 Ethiopian hymns across Amharic, Afaan Oromo, and Ge'ez scripts, offline-first was not an enhancement—it was the baseline requirement. If the user cannot read a hymn in church with zero cell service, the application has failed.
Why lyrics apps fail on spotty networks
Most modern web applications treat the server as the single source of truth and the browser as a dumb terminal. When the network stalls, the user is greeted by empty skeleton screens and spinning loaders that eventually crash into error toasts.
For textual content like hymns, poetry, and reference documents, this architecture is fundamentally broken. The total dataset for thousands of hymns is barely four megabytes of compressed JSON. Waiting on a round-trip to read 300 words of text is an architectural failure.
IndexedDB caching and delta updates
We turned the browser into a first-class local database using IndexedDB managed through a lightweight repository layer. On initial boot, the app seeds its local store from a bundled snapshot, making first paint instant even with no connection.
To sync additions and edits without re-downloading megabytes of repetitive content, the client sync worker sends its last_sync_timestamp. The NestJS backend queries PostgreSQL using indexed audit timestamps and returns only the delta changeset.
const syncDeltas = async (sinceTimestamp: number) => {
const response = await fetch(`/api/sync?since=${sinceTimestamp}`);
const { updatedHymns, deletedIds, serverTime } = await response.json();
await db.transaction('rw', db.hymns, async () => {
await db.hymns.bulkPut(updatedHymns);
await db.hymns.bulkDelete(deletedIds);
});
localStorage.setItem('last_sync_timestamp', serverTime);
};Fast full-text search across scripts
Searching multilingual Ethiopic text offline presents unique Unicode normalization challenges. Ge'ez script characters possess different orthographic representations across dialects (such as ሀ, ሐ, ኀ, or ጸ and ፀ) that users expect to match phonetically regardless of spelling variation.
We implemented an in-memory inverted index that runs entirely on client web workers. By indexing normalized phonetic tokens at startup, queries execute in sub-4ms times directly on device, providing instant search filtering without a single packet leaving the phone.
