Skip to content

pranshuchittora/react-native-duckdb

Repository files navigation

React Native DuckDB

npm version MIT License Platform DuckDB Version


The analytical database for React Native. Run OLAP queries, full-text search, and vector similarity search on iOS and Android with native C++ performance via Nitro Modules.

  • Columnar OLAP engine (not row-based OLTP like SQLite)
  • Full-text search with BM25 ranking and 27 language stemmers
  • Vector similarity search with HNSW indexing for on-device RAG/AI
  • Remote data queries over HTTPS (Parquet, CSV, JSON, Hugging Face datasets)
  • Streaming results for large datasets without OOM
  • Bulk insert via Appender API
  • Columnar typed array access (Float64Array, BigInt64Array)
  • 30+ DuckDB types including HUGEINT, DECIMAL, ARRAY, MAP, STRUCT
  • Query cancellation, progress callbacks, JSON profiling
  • Expo config plugin for managed workflow

Try It Now

Download DuckDB Explorer — a free companion app to try everything before writing a single line of code. Interactive SQL runner, Hugging Face dataset browser, full-text search, vector similarity search, and more.

App Store   Google Play

Installation

npm install react-native-duckdb react-native-nitro-modules

For iOS, run pod install after installation.

Quick Start

import { HybridDuckDB } from 'react-native-duckdb'

const db = HybridDuckDB.open(':memory:', {})

db.executeSync('CREATE TABLE users (id INTEGER, name VARCHAR, score DOUBLE)')
db.executeSync("INSERT INTO users VALUES (1, 'Alice', 95.5), (2, 'Bob', 87.3)")

const result = db.executeSync('SELECT * FROM users ORDER BY score DESC')
const rows = result.toRows()
// [{ id: 1, name: 'Alice', score: 95.5 }, { id: 2, name: 'Bob', score: 87.3 }]

db.close()

Features

Configuration

const db = HybridDuckDB.open(':memory:', {
  threads: '2',
  memory_limit: '256MB',
  default_order: 'DESC',
})

Async Execution

const result = await db.execute('SELECT * FROM large_table WHERE category = ?', ['electronics'])
const rows = result.toRows()

Prepared Statements

const stmt = db.prepare('SELECT * FROM users WHERE age > ?')
stmt.bind([21])
const result = stmt.executeSync()
stmt.finalize()

Named Parameters

const result = db.executeSyncNamed(
  'SELECT * FROM users WHERE name = $name AND age > $age',
  { $name: 'Alice', $age: 21 }
)

Query Cancellation

const promise = db.execute('SELECT * FROM generate_series(1, 100000000)')
setTimeout(() => db.cancel(), 50)

Profiling

db.executeSync("PRAGMA enable_profiling='json'")
db.executeSync('SELECT * FROM large_table ORDER BY score DESC')
const profile = db.getProfilingInfo() // JSON string with timing breakdown

Progress Callbacks

db.setProgressCallback((percentage) => {
  console.log(`Query progress: ${percentage}%`)
})
const result = await db.execute('SELECT * FROM big_join')
db.removeProgressCallback()

Batch Execution

const { rowsAffected } = db.executeBatchSync([
  { query: 'INSERT INTO logs VALUES (?, ?)', params: [1, 'start'] },
  { query: 'INSERT INTO logs VALUES (?, ?)', params: [2, 'end'] },
])

Transactions

import { executeTransaction } from 'react-native-duckdb'

const count = await executeTransaction(db, async (tx) => {
  tx.executeSync('INSERT INTO orders VALUES (1, 99.99)')
  tx.executeSync('UPDATE inventory SET stock = stock - 1 WHERE id = 1')
  return tx.executeSync('SELECT count(*) as n FROM orders').toRows()[0].n
})
// auto-commits on success, auto-rolls-back on error

Multi-Database

db.attach('/path/to/other.duckdb', 'analytics', { readOnly: true })
const result = db.executeSync('SELECT * FROM analytics.events LIMIT 10')
db.detach('analytics')

Database Paths

import { DOCUMENTS_PATH, LIBRARY_PATH } from 'react-native-duckdb'

const db = HybridDuckDB.open(`${LIBRARY_PATH}/analytics.duckdb`, {})
// iOS: NSLibraryDirectory (no iCloud backup)
// Android: getFilesDir()

See docs/database-location.md for all available paths, backup behavior, and platform details.

Delete Database

HybridDuckDB.deleteDatabase(`${DOCUMENTS_PATH}/old.duckdb`)

Streaming Large Datasets

Process millions of rows chunk-by-chunk without loading everything into memory.

import { streamChunks } from 'react-native-duckdb'

const stream = await db.stream('SELECT * FROM large_table')
for await (const chunk of streamChunks(stream)) {
  processChunk(chunk.toRows())
}

See docs/streaming.md for the Appender API, progress callbacks, and ETL patterns.

Full-Text Search

BM25-ranked search with 27 language stemmers. Requires the fts extension.

db.executeSync("LOAD 'fts'")
db.executeSync("PRAGMA create_fts_index('docs', 'id', 'title', 'body', stemmer='english')")

const results = db.executeSync(`
  SELECT *, fts_main_docs.match_bm25(id, 'search query') AS score
  FROM docs WHERE score IS NOT NULL ORDER BY score DESC
`)

See docs/fts.md for multi-language stemming, field-specific search, and limitations.

Vector Similarity Search

HNSW-indexed nearest-neighbor queries for on-device semantic search and RAG. Requires the vss extension.

db.executeSync("LOAD 'vss'")
db.executeSync('CREATE TABLE docs (id INTEGER, vec FLOAT[384])')
db.executeSync("CREATE INDEX idx ON docs USING HNSW (vec) WITH (metric = 'cosine')")

const similar = db.executeSync(`
  SELECT id, array_cosine_distance(vec, $query::FLOAT[384]) AS distance
  FROM docs ORDER BY distance LIMIT 10
`)

See docs/vss.md for distance metrics, use cases, and HNSW tuning.

Extensions

Extensions are statically linked at build time. Configure in package.json (bare) or app.json (Expo):

{
  "react-native-duckdb": {
    "build": {
      "extensions": ["core_functions", "parquet", "json"]
    }
  }
}
Extension Description
core_functions Essential SQL functions (sum, avg, uuid, etc.) — recommended
parquet Apache Parquet file format
json JSON file format
httpfs Remote file access over HTTPS
fts BM25 full-text search
vss HNSW vector similarity search
sqlite_scanner Read SQLite databases
icu Unicode collation and locale
delta Delta Lake table format
autocomplete SQL autocomplete
tpch / tpcds Benchmark data generators

See docs/extensions.md for configuration details and per-extension guides.

Expo: Add to app.json plugins:

["react-native-duckdb", { "extensions": ["core_functions", "parquet"] }]

See docs/expo.md for the full Expo guide.

How It Compares

react-native-duckdb is an OLAP (Online Analytical Processing) database — optimized for analytical queries over large datasets. The libraries below are OLTP (Online Transaction Processing) databases — optimized for many small read/write transactions typical in app state management.

These are complementary paradigms. Use SQLite-based libraries for your app's transactional data (users, settings, state). Use DuckDB for analytics, search, and data processing.

Feature react-native-duckdb nitro-sqlite op-sqlite WatermelonDB
Engine DuckDB (columnar OLAP) SQLite (row OLTP) SQLite (row OLTP) SQLite (row OLTP)
Native bridge Nitro Modules (JSI) Nitro Modules (JSI) JSI JSI
Parquet/CSV/JSON file queries Yes No No No
Remote data (HTTPS) Yes (httpfs) No No No
Full-text search BM25 with 27 stemmers FTS5 (compile flag) FTS5 (compile flag) No
Vector search (HNSW) Yes No sqlite-vec plugin No
Columnar typed arrays Yes (Float64Array, etc.) No No No
Streaming results Yes (chunk-by-chunk) No No No
Bulk insert (Appender) Yes No No Batch insert
Query progress callbacks Yes No No No
Reactive queries No No Yes Yes
ORM / Model layer No (raw SQL) TypeORM compatible TypeORM compatible Built-in
Sync protocol No No No Built-in
Encryption No No SQLCipher No
Expo plugin Yes No No No

Documentation

Guide Description
API Reference Complete API surface — every method, property, and type
Extensions Configuration, available extensions, per-extension usage
Streaming & Appender Chunk-by-chunk processing, bulk insert, ETL patterns
Type System DuckDB → JavaScript type mapping for all 30+ types
Transactions ACID transactions, batch execution, multi-database
Database Location Storage paths, iCloud/Auto Backup, platform defaults
Full-Text Search BM25 indexing, stemmers, field search, limitations
Vector Search HNSW indexes, distance metrics, RAG patterns
Remote Data httpfs, Hugging Face datasets, S3, TLS config
Expo Setup Config plugin, extension flow, migration guide
Bare Workflow iOS/Android setup without Expo

Built with AI

I started working on this library in late 2023. The initial prototype took a full week and could barely run basic SQL statements — no extensions, no streaming, no type system. It proved the concept but was nowhere near production quality.

Fast forward to Feb 2026: with the help of LLMs, I rebuilt the entire library from scratch — production-grade, fully documented, with 11 statically-linked extensions, 30+ type mappings, streaming, vector search, full-text search, and an example app that doubles as a DuckDB dev studio. The entire rebuild took under one week.

The stack: Claude Opus 4 (claude-4-6) running through opencode, orchestrated by the Get Shit Done framework for structured multi-phase execution. The total inference cost was roughly ~$1,500.

But here's the thing — AI didn't make the decisions. I have extensive experience building React Native libraries, especially data libraries, and every architectural choice, every API design trade-off, every verification pass, every device test was done by a real human. The AI handled the volume; I handled the vision.

We're at the beginning of something massive. A single developer with the right tools can now ship what used to require a dedicated team and months of runway. The barrier to building ambitious software is collapsing. This library is proof.

License

MIT


Inspired by react-native-nitro-sqlite and op-sqlite. Built with DuckDB and Nitro Modules. See RELEASE.md for release security details.