(updated)
|
min. read

React Native Local Database Options: A Comprehensive Summary

Kobie Botha

Local-First for React Native

A few years ago, the only reason to consider a local-first app architecture was if advanced offline functionality was a hard requirement for your app[1]. More recently though, giving users a real-time collaborative UX (like Figma) has been enticing enough for more developers to venture down the path of local-first.

In particular, the interest in building React Native apps with local-first architecture is on the rise. New tools and tutorials[2] make it easier than ever to get started with a local-first React Native app. More and more developers are realizing that local-first is not simply a way to provide certain features (e.g. real-time reactive UI, offline mode, real-time collaboration), but rather an architecture that avoids a lot of the complexities that come with modern cloud-first apps (e.g. caching, optimistic updates, etc.)

Part of what makes local-first appealing for React Native is that it inherently provides a simple approach to state management. There are many good state management frameworks available like Zustand, Redux and MobX, but local-first provides a different paradigm: using a local database (e.g. SQLite) to manage state[3]. Coupled with tools like Kysely (a SQL query builder) and TinyBase (a reactive in-memory data store), using a local database for state management becomes even more accessible.

React Native Local Database Options

The growing interest in local-first architectures for React Native led us to further explore the various local database options in the React Native ecosystem. Evaluating each requires diving a bit deeper into their code, and also having an idea of what you’re looking for.

We created the table below to show the main options available with key features that should help you decide which local database will work best for you. Good luck!

Preface

This breakdown only consists of local database options that provide full database functionality (persistent, consistent and queryable data stores). We ignored less-featured databases and caches. For example, we haven’t included react-native-mmkv or async-storage.

All of the below databases are open-source.

Comparison Table

Database / Package Description Type Asynchronous by Default? Concurrency Encryption Support Web Support Query Method Plug-in Cloud Sync Support Backend Database Type

react-native-nitro-sqlite

Nitro SQLite embeds the latest version of SQLite and provides a low-level JSI-backed API to execute SQL queries.

A fork of the original react-native-quick-sqlite (by ospfranco), which was deprecated in favour of OP-SQLite.

SQLite

Yes (has equivalent synchronous and asynchronous APIs for most operations)

No (single read or write transaction at a time)

No

No

SQL

No

-

powersync-react-native-quick-sqlite

Fork of react-native-quick-sqlite with some optimisations and enhancements. Note: This is not meant to be used directly, without PowerSync. [4]

SQLite

Yes

Yes (built-in support for one write transaction and multiple read transactions concurrently)

No (use OP-SQLite instead)

No

SQL

Yes (via PowerSync)

Postgres, MySQL, MongoDB

op-sqlite

Embeds the latest version of SQLite and provides a low-level API to execute SQL queries.

SQLite

Yes (has equivalent synchronous and asynchronous APIs for most operations)

Yes (multiple connections supported)

Yes (via SQLCipher)

No

SQL

Yes (via PowerSync)

-

expo-sqlite

Provides access to a SQLite database that can be queried through a WebSQL-like API.

SQLite

Yes (has equivalent synchronous and asynchronous APIs for most operations)

Likely yes (via WAL and manual connections)

Yes (via SQLCipher)

Yes (via WA-SQLite)

SQL

Yes (via PowerSync)

-

WatermelonDB

Database framework that provides high-level abstractions for SQLite.

SQLite

Yes

No (single Reader or Writer at a time)

No

Yes

ORM [5]

Yes (bring your own backend implementation)

Backend-specific

RxDB

NoSQL database made for JavaScript applications supporting various underlying storage layers.

NoSQL

Yes

Unknown

Yes via encryption-crypto-js

Yes

Domain-specific

Yes (e.g. with CouchDB server or any custom GraphQL endpoint)

NoSQL

LiveStore

LiveStore is a next-generation state management framework based on reactive SQLite and git-inspired syncing (via event-sourcing).

SQLite

No. Queries are performed against a synchronous in-memory DB. This DB is persisted asynchronously. Docs

No. Queries are executed synchronously on the main thread.

No (docs)

Yes

ORM with the ability to perform custom SQL queries.

Yes (docs)

  • CloudFlare Workers
  • ElectricSQL
  • S2 (planned)
  • Custom sync integration

  • CloudFlare syncing uses D1 (SQLite compatible) to persist LiveStore events.
  • Postgres DB used to store mutation event history when using ElectricSQL

Realm (deprecated)

Object database originally maintained by Realm, then MonogoDB.

NoSQL

Yes

Unknown

Yes

Yes

Domain-specific

No (MongoDB Atlas Device Sync support deprecated)

NoSQL

Notes On Table Columns

Type

Indicates whether the database is SQLite-based or NoSQL.

Asynchronous by Default

Indicates whether the database supports asynchronous operations; in other words, whether there is support that prevents the main thread from being blocked.

Concurrency

This refers to the database’s ability to support multiple concurrent transactions.

Encryption Support

Whether the database supports encryption, and if so, how.

Web Support

This refers to the library being compatible with plain JavaScript web or frameworks.

Query Method

Here the query methods are "SQL" or "ORM" for SQLite-based databases and "domain-specific" for NoSQL databases since they each have their own query syntax flavor.

Plug-In Cloud Sync Support

This refers to the database’s ability to plug into an existing sync system that keeps data in sync with a primary cloud database and across multiple devices.

Backend Database Type

This indicates the database type that the database sync solution supports.

Feedback

If you have feedback on this summary or have a suggestion for a feature or database to include, please let us know on our Discord server.

Footnotes

[1] The concept of “offline-first” is a predecessor to “local-first” and there’s overlap between the two concepts.

[2] See an example here.

[3] See a previous post on local-first state management with SQLite for more on that.

[4] This will be available as a general-purpose SQL library in the near future.

[5] SQL is possible but discouraged.