Skip to content

SQLite

UQL speaks SQLite through three drivers. All of them produce identical SQL and identical results; they differ only in what you have to install and how fast they read.

Pool Driver Install
NodeSqliteQuerierPool Node’s built-in node:sqlite nothing
Sqlite3QuerierPool better-sqlite3, or bun:sqlite under Bun npm i better-sqlite3 (Bun needs nothing)
HranaQuerierPool libSQL / Turso over the wire see Turso

NodeSqliteQuerierPool uses the SQLite that ships inside Node, so there is no native module to build and nothing to install:

import { NodeSqliteQuerierPool } from 'uql-orm/sqlite';
export const pool = new NodeSqliteQuerierPool('app.db');

That matters most where a native build is awkward: slim container images, CI without a toolchain, and anywhere node-gyp is unwelcome. UQL requires Node 24, which is well past the 22.13 where node:sqlite became usable, so there is no version to check.

Loadable extensions work too, which is what vector search needs, since SQLite ships no vector functions of its own:

import { getLoadablePath } from 'sqlite-vec';
const pool = new NodeSqliteQuerierPool('app.db', { extensions: [getLoadablePath()] });

better-sqlite3 is faster on reads. Measured on 20k in-memory rows, node:sqlite was about 20% quicker on inserts but 1.3x slower on point reads and 1.4x slower on 100-row reads. Reads dominate most workloads, so better-sqlite3 stays the recommendation when throughput matters and installing a native module is not a problem.

node:sqlite is also still a release candidate in Node’s own stability index, while better-sqlite3 is long settled.

import { Sqlite3QuerierPool } from 'uql-orm/sqlite';
export const pool = new Sqlite3QuerierPool('app.db');

Under Bun this same pool uses bun:sqlite automatically, so Bun projects install nothing either.

Every querier releases itself when an await using binding goes out of scope, however the block exits:

await using querier = await pool.getQuerier();
const users = await querier.findMany(User, {});