Every React Native app hits the same wall: you ship with AsyncStorage or MMKV, things work for the first 100 users, then someone with 5,000 records opens the app and it takes six seconds to load.
That wall is the storage layer. AsyncStorage is a key-value store — fine for tokens and preferences, broken for any real data. SQLite is fast but verbose. Realm is powerful but heavy.
WatermelonDB is the answer for serious offline-first apps. It's SQLite under the hood, lazy-loaded, observable, and ships with a sync protocol. Here's the actual setup.
Why WatermelonDB (and not the alternatives)
| Option | Good for | Problem |
|---|---|---|
| AsyncStorage | Tokens, prefs | Reads block the JS thread past a few hundred items |
| MMKV | Fast key-value | Same limitations as AsyncStorage — no queries |
| SQLite (raw) | Anything | No ORM, no observables, you write sync yourself |
| Realm | Anything | Heavy native binary, sync costs money, lock-in |
| WatermelonDB | Offline-first apps | Learning curve, you write sync (but the protocol is spec'd) |
WatermelonDB is built for the case where your data outgrows key-value storage and you need real offline sync. It lazy-loads records — a list of 10,000 items renders instantly because only the visible rows are loaded into JS memory.
Step 1: Install and configure
npm install @nozbe/watermelondb
npm install --save-dev @babel/plugin-proposal-decorators