expo-sqlite vs op-sqlite: Which SQLite Library Should You Use in React Native?
Both expo-sqlite and op-sqlite bring local SQLite storage to React Native apps, but they take very different paths to get there. Here's what actually matters when choosing between them.
Ahmad Tarabein
Software Developer · May 25, 2026
SQLite has always been the go-to for local storage in mobile apps that need something more structured than AsyncStorage but don't want the overhead of a backend. In React Native, two libraries own that space right now: expo-sqlite and op-sqlite. On the surface they solve the same problem. Dig a little deeper and they make very different bets.
A Tale of Two Architectures
expo-sqlite is the official SQLite solution from the Expo team. Older versions communicated with native code through the React Native bridge, a serialization-heavy channel that converts JavaScript values to JSON, ships them across a thread boundary, and deserializes them on the other side. It was fine for light query loads. For anything doing real work, it was a bottleneck.
That changed with Expo SDK 50. The revamped v14 API is built on JSI (JavaScript Interface), which allows direct synchronous calls into native code without JSON serialization. You get a proper synchronous API through useSQLiteContext and openDatabaseSync, first-class prepared statements, and solid transaction support. It's a meaningful upgrade from where the library was two years ago.
op-sqlite was built from the ground up with JSI at its core. Oscar Franco created it with one goal in mind: performance. There's no legacy bridge path and no optional synchronous mode because the whole library is synchronous. It also gives you far more control over the underlying SQLite build. You can swap in a custom SQLite version, enable WAL mode explicitly, or use libSQL (the open-source fork behind Turso) to layer replication on top of your local database.
Both libraries are fast in 2026, but op-sqlite pulls ahead in benchmarks, especially for write-heavy workloads or tight loops over large result sets. In a typical CRUD app you probably won't feel the difference. If you're building something local-first with frequent sync operations, or processing large datasets on device, that throughput gap starts to matter.
Developer Experience
This is where the two libraries diverge most obviously. expo-sqlite wins on ergonomics. It's part of the Expo ecosystem, so npx expo install expo-sqlite and you're running. No native configuration needed. The React hooks-based API integrates naturally with component trees. Drizzle ORM has official support for it, which means migrations, type-safe queries, and schema management come along almost for free. Documentation is thorough, issues are actively monitored, and breaking changes come with migration guides.
op-sqlite is rougher around the edges. You'll need to run pod install on iOS and there's more manual configuration to get through. The API is lower-level. You get open, execute, executeAsync, and transaction helpers, but no built-in React context or hooks layer. It integrates with Drizzle and works fine with TypeScript, but you're doing more of the wiring yourself.
For teams already deep in the Expo ecosystem using EAS Build, Expo Router, and managed workflow, expo-sqlite is the obvious pick. It requires no ejection and plays nicely with everything else Expo manages. For bare React Native projects where you're already handling native dependencies yourself, op-sqlite's setup overhead is manageable and you get a higher performance ceiling in return.
Features Worth Knowing About
Both libraries support prepared statements and parameterized queries, both support transactions including nested ones via savepoints, and both have async APIs for offloading work from the UI thread. Enabling WAL mode is recommended with either one since it dramatically improves concurrent read/write performance.
Where op-sqlite goes further is its extended feature set. It ships with optional SQLCipher support for at-rest encryption, useful for apps that handle sensitive user data. There's a plugin system for custom SQLite extensions. The libSQL adapter opens up local-first sync with a remote Turso database, which is genuinely interesting if you're exploring that architecture.
expo-sqlite counters with better tooling. The Expo team maintains a SQLite extension for Expo Dev Tools that lets you inspect your database in real time during development. The v14 API also introduced live queries, where a query result can reactively update a component when the underlying data changes without manually setting up listeners.
Which One to Use
Three questions usually decide it: Are you in a managed Expo workflow? Do you need maximum performance or specific native features like encryption? How much setup friction can you stomach?
For a standard Expo app, expo-sqlite v14+ is excellent. The performance gap over the old bridge is largely closed, the React primitives are clean, and you're not fighting your toolchain. For bare React Native, strict performance requirements, encryption needs, or local-first sync with libSQL, op-sqlite is worth the extra configuration.
The ecosystem converging on Drizzle helps too. Your schema and query code stays portable between both libraries, so if you start with one and hit its limits, migration isn't the nightmare it used to be. Both are actively maintained, both have production deployments at scale, and both are genuinely good options in ways that weren't true just a few years ago.


