Engineering
April 25, 2024
April 26, 2024
(updated)

React Native Local Database Options: A Comprehensive Summary

Mugi Khan

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, giving users a real-time collaborative UX (like Figma) has been enticing enough for more developers to venture down the path of local-first.

Today, the interest in building React Native apps with local-first architecture seems to be rising still. New tools and tutorials[2] make it easier than ever to get started with a local-first React Native app. There seems to be a broader paradigm shift taking place: 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.

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

react-native-quick-sqlite

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

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 (planned for future)

No

SQL

Yes (when used as part of PowerSync)

SQL

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)

No (single read or write transaction at a time)

Yes (via SQLCipher)

No

SQL

No

-

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)

No (single read or write transaction at a time)

No

No

SQL

No

-

expo-sqlite/next

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

SQLite

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

No (single read or write transaction at a time)

No

No

SQL

No

-

WatermelonDB

Database framework that provides high-level abstractions for SQLite.

NoSQL

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

Realm (now part of MongoDB)

Realm is an object database system. Realm has its own database engine and doesn′t just rely on key-value pairs.

NoSQL

Yes

Unknown

Yes

Yes

Domain-specific

Yes (through MongoDB Atlas Device Sync)

NoSQL (Hosted MongoDB Atlas)

Notes On Table Columns

Type

Indicates whether the database is SQLite-based or NoSQL.

Asynchronous by Default

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

Web Support

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

Concurrency

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

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 cloud database type that the cloud 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.