Lumosql

Documentation
Login

Documentation

Node.js better-sqlite3 backed by LumoSQL

better-sqlite3 is the most popular SQLite binding for Node.js. This directory builds better-sqlite3 against LumoSQL with the LMDBv1 backend. Besides being faster for most operations, LMDBv1 behind the SQLite interface allows page-based encryption, incremental backup and checksums without further development because these are core features of LMDBv1.

The Makefile replaces only the vendored deps/sqlite3/sqlite3.c and sqlite3.h, copies the LumoSQL helper files into deps/lumo/, and extends deps/sqlite3.gyp.

The LumoSQL backend can also be built with traditional LMDB (in deep freeze maintenance as of July 2026, and occasionally still a little faster than v1.0 on some operations). To do this use something like BACKEND_SPEC=lmdb-0.9.35 LUMOSQL_TARGET=3.53.3+lmdb-0.9.35. We mostly just use LMDBv1.

Dependencies

Install the normal LumoSQL build dependencies from the top-level README and confirm them with:

make doctor

In addition, this example needs Node.js 20 or newer, npm, git, python3, make, and a C++ compiler.

Debian/Ubuntu:

sudo apt install git nodejs npm python3 make g++

Fedora/RHEL:

sudo dnf install git nodejs npm python3 make gcc-c++

Quick build

From the LumoSQL root directory:

make doctor
cd examples/node-better-sqlite3
make

The addon is:

examples/node-better-sqlite3/build/better-sqlite3/build/Release/better_sqlite3.node

Confirm LumoSQL is linked statically:

ldd build/better-sqlite3/build/Release/better_sqlite3.node | grep -i sqlite   # expect: no output

By default the Makefile builds better-sqlite3 v12.11.2, detects the SQLite version it bundles, and builds the matching +lmdbv1-1.0 LumoSQL target. Override the defaults as follows:

make BSQL_REF=master
make LUMOSQL_TARGET=3.53.3+lmdbv1-1.0
make BSQL_GIT_URL=https://github.com/WiseLibs/better-sqlite3 WORK_DIR=/tmp/lumo-bsql

If better-sqlite3 master bundles a SQLite version newer than LumoSQL has (pretty unlikely), the Makefile falls back to LumoSQL's newest SQLite.

Smoke test

make smoke

The smoke test creates a throwaway database, exercises prepared statements, transactions, .get(), .all(), .iterate(), a user-defined function, and FTS5. It also prints the result of PRAGMA journal_mode=WAL, because WAL is a SQLite pager feature and is a no-op under the LMDB backend. The test verifies that the database file has the LMDB magic bytes and a <db>-lock sibling, and no -wal or -shm files.

To try the built module from another project:

npm install /path/to/lumosql/examples/node-better-sqlite3/build/better-sqlite3

Testing, and Unimplemented features and deviations

Run the upstream better-sqlite3 test suite through the example Makefile:

make test

This runs each upstream better-sqlite3/test/*.js file separately with test/00.setup.js loaded first, so one expected LMDB/file-format failure does not hide later results.

npm run benchmark is not a stock-vs-LumoSQL comparison for this build. The upstream benchmark seeds one database through better-sqlite3; here that file is LMDB-format, so the comparison drivers that expect SQLite file format (node-sqlite3 and node:sqlite) fail with SQLITE_NOTADB. You should read only the better-sqlite3 result rows from that benchmark, or, use LumoSQL's own benchmark suite for native-vs-LMDB comparisons. Features tied to SQLite's pager or file format are absent or no-op under the LMDB backend including backup(), serialize(), deserialize(), checkpointing, WAL pragmas, and tests that fabricate or inspect SQLite file-format bytes. Test suite entries for these features (including ones that expect particular bytes to be present in a data file) will fail. Look at the directory better-sqlite3/test/*js to see what upstream tests do. The result should be that all relevant tests pass identically with both LMDB backends.

Note: better-sqlite3 builds SQLite with SQLITE_THREADSAFE=2, and this LumoSQL example keeps that upstream setting. This varies from LumoSQL's own tests which assume SQLITE_THREADSAFE=1.

LMDB databases always have a <db>-lock file, analogous to SQLite<db>-wal and <db>-shm files that are often generated when native SQLite runs in WAL mode.

Data migration

An LMDB-backed LumoSQL database is not an SQLite file-format database, with conversion left to the user. As an example, you can copy rows from an existing SQLite database into a new LMDB-backed one like this:

const Stock = require('/path/to/stock/node_modules/better-sqlite3');
const Lumo = require('/path/to/lumosql/examples/node-better-sqlite3/build/better-sqlite3');
const src = new Stock('old.sqlite');
const dst = new Lumo('new.lmdb');
dst.exec('CREATE TABLE t(id INTEGER PRIMARY KEY, body TEXT)');
const insert = dst.prepare('INSERT INTO t VALUES (?, ?)');
dst.transaction(() => src.prepare('SELECT id, body FROM t').iterate().forEach((r) => insert.run(r.id, r.body)))();