WatermelonDB vs SQLite vs Realm in 2026
WatermelonDB vs SQLite vs Realm for React Native in 2026: performance, sync, the end of Atlas Device Sync, and which local database to choose.
Full-Stack, Mobile & AI Engineer
Choosing a local database for a React Native app used to be a three-way debate: plain SQLite, WatermelonDB, or Realm with MongoDB's sync. In 2026 the field looks different. MongoDB ended Atlas Device Sync in September 2025, SQLite tooling for React Native has improved dramatically, and WatermelonDB remains the specialist for very large, reactive datasets.
This guide compares WatermelonDB vs SQLite vs Realm as they stand now: how each works, what each is good at, what the end of Device Sync means for Realm users, and which to choose for a new app.
Key takeaways
- SQLite (via
expo-sqliteorop-sqlite, often with Drizzle) is the default local database for most React Native apps in 2026. - WatermelonDB builds on SQLite with lazy loading, reactive queries and a sync protocol, and shines with tens of thousands of records.
- Realm's cloud sync is gone: MongoDB deprecated Atlas Device Sync in September 2024 and ended it on 30 September 2025. Realm continues as an open-source local database, without MongoDB's sync.
- Sync is a separate decision. Choose a database for local storage, then a sync approach (your own API, WatermelonDB's protocol, or a sync platform).
- For new apps: SQLite with Drizzle unless you know you need WatermelonDB's scale features.
The comparison
| SQLite (expo-sqlite / op-sqlite) | WatermelonDB | Realm | |
|---|---|---|---|
| Built on | SQLite | SQLite, with its own layer | Its own object database |
| Querying | SQL, or an ORM like Drizzle | Its query API with lazy loading | Object queries |
| Reactivity | Live queries via tools (e.g. Drizzle's live queries) | Built in: components re-render on change | Built in |
| Large datasets | Good with indexes and pagination | Excellent; loads records lazily | Good |
| Sync | Bring your own | Sync protocol with your backend (pull and push) | MongoDB Device Sync ended; local only now |
| Maturity in 2026 | Very active | Mature, specialist | Uncertain long-term direction for mobile |
SQLite: the default
SQLite is everywhere, extremely well tested, and now has excellent React Native bindings. expo-sqlite provides async and sync APIs and works with Expo out of the box; op-sqlite is a fast JSI-based alternative for bare and Expo apps. Add Drizzle ORM for typed schemas, queries and migrations, and you have a modern, maintainable data layer.
Choose it when: you want a standard, portable database with full SQL; your datasets are small to large but not enormous; you'll build sync against your own API.
Getting started: React Native with SQLite
expo-sqlite works in Expo Go and in bare apps, with an async API:
import * as SQLite from "expo-sqlite";
const db = await SQLite.openDatabaseAsync("app.db");
await db.execAsync(
"CREATE TABLE IF NOT EXISTS notes (id TEXT PRIMARY KEY NOT NULL, body TEXT, updated_at INTEGER);",
);
await db.runAsync("INSERT INTO notes (id, body, updated_at) VALUES (?, ?, ?)", id, body, Date.now());
const notes = await db.getAllAsync<Note>("SELECT * FROM notes ORDER BY updated_at DESC");Always pass values as parameters (the ? placeholders) rather than building SQL strings, and run schema changes as numbered migrations.
SQLite libraries and ORMs
| Option | What it is | When to use it |
|---|---|---|
expo-sqlite | Expo's SQLite module, async and sync APIs | The default for most apps |
op-sqlite | A fast JSI-based SQLite library | Heavy query workloads where speed matters |
| Drizzle ORM | A typed query builder with migrations, with an expo-sqlite driver | Teams who want typed queries instead of raw SQL |
| WatermelonDB | A reactive database layer on top of SQLite, with a sync protocol | Large datasets that screens observe |
WatermelonDB: built for big, reactive datasets
WatermelonDB was designed for apps with tens of thousands of records that must stay fast on low-end Android phones. It loads records lazily (only what's on screen), runs queries off the JavaScript thread, and re-renders components automatically when their data changes. It also defines a sync protocol: your backend implements "pull changes since X" and "push these changes", and WatermelonDB handles the rest on the device.
Choose it when: you have large local datasets (messaging, field data, catalogs), need reactive UI over them, and want a ready-made sync protocol.
Trade-offs: its own data model and API to learn, and more setup than plain SQLite.
Realm after Device Sync
MongoDB announced in September 2024 that Atlas Device Sync and the Atlas Device SDKs were deprecated, and Device Sync reached end-of-life on 30 September 2025. The Realm SDK remains available as an open-source local database, but recent versions don't include cloud synchronisation, and App Services features built around the SDKs were deprecated too.
What that means in practice:
- New apps shouldn't start on Realm for synced data.
- Existing apps that used only local Realm can keep running, but should weigh the long-term maintenance outlook.
- Apps that relied on Device Sync need a new sync approach: migrate local data to SQLite or WatermelonDB and sync through their own API or a sync platform such as PowerSync.
WatermelonDB with Expo and Supabase
WatermelonDB includes native code, so it needs a development build (not Expo Go) and a config plugin, which the community maintains. With Supabase or any Postgres backend, you implement WatermelonDB's two sync endpoints yourself, "pull changes since" and "push these changes", typically as database functions or API routes that read and write by updated_at and handle deletions explicitly.
Choosing sync separately
Your database stores data on the device. Sync moves it to and from your server. Options:
| Sync approach | Fits when |
|---|---|
| Your own REST or GraphQL API with an outbox | You control the backend and data model |
| WatermelonDB's sync protocol | You use WatermelonDB and can implement pull and push endpoints |
| A sync platform (for example PowerSync with Postgres) | You want sync handled by a service and use a supported backend |
From the field: MMKV, SQLite and WatermelonDB are all in my offline-first toolkit, and I've built offline-first sync for an app with 100K+ active users that kept workout data safe through network drops. Whatever the database, it's the sync rules, idempotency and conflict handling that decide whether users' data stays safe.
Migrating between databases
Moving users from one local database to another is mostly a data-copy problem with one rule: never lose data that hasn't synced yet. Ship a version that reads the old store, writes everything into the new one in a transaction, verifies counts, and only then marks the migration complete. Keep the old store until the following release, and sync pending changes before switching, so a failed migration can be retried rather than recovered.
My recommendation for a new app
- Start with SQLite plus Drizzle for anything relational or offline.
- Use MMKV for small key-value state alongside it.
- Reach for WatermelonDB when profiling shows large local datasets or reactive updates are a real bottleneck.
- Design sync as its own layer, with client-generated IDs, an outbox and idempotent endpoints, whichever database you choose.
FAQ
Is WatermelonDB better than SQLite?
WatermelonDB is built on SQLite and adds lazy loading, reactive queries and a sync protocol, which make it better for very large datasets and reactive UIs. For most apps, plain SQLite with an ORM like Drizzle is simpler and entirely sufficient.
Is Realm deprecated?
MongoDB deprecated Atlas Device Sync and the Atlas Device SDKs in September 2024, and Device Sync ended on 30 September 2025. The Realm database continues as open source for local storage without cloud sync, so new apps that need sync should choose another approach.
What should I use instead of Realm Device Sync?
Move local data to SQLite or WatermelonDB and sync through your own API (with an outbox and idempotent endpoints), WatermelonDB's sync protocol, or a sync platform such as PowerSync. Plan the migration so existing users' local data is preserved.
Which database is best for offline-first React Native apps?
SQLite is the best default, via expo-sqlite or op-sqlite, ideally with Drizzle for typed queries. Choose WatermelonDB when you have tens of thousands of records and need reactive updates. Combine either with MMKV for small settings and secure storage for credentials.
Next steps
If you're choosing a local database, or need to move off Realm after Device Sync ended, I can design the data layer and the migration so users don't lose anything. Get in touch, or see how I work as a React Native developer.
Sources
- SQLite (expo-sqlite), Expo documentation
- Drizzle ORM with Expo SQLite, Drizzle
- SQLite (expo-sqlite), Expo
- WatermelonDB documentation, WatermelonDB
- Atlas Device Sync deprecation notice, MongoDB Community
- Drizzle with Expo SQLite, Drizzle ORM
- op-sqlite, GitHub
Related
Offline-First React Native: Lessons from an App with 100K Users
How to build offline-first React Native apps that never lose data: local-first storage, an outbox for writes, sync, conflicts and testing bad networks.
MMKV vs AsyncStorage vs SQLite: Picking Local Storage
MMKV vs AsyncStorage vs SQLite for React Native in 2026: speed, data shape, encryption and size limits, which to use for what, and how to migrate.
Sync Conflicts in Mobile Apps: Strategies That Don't Lose Data
How to resolve offline sync conflicts in mobile apps: last-write-wins, versions, merges, CRDTs, append-only data, server authority, clocks and testing.
