> Every UQL docs page, as Markdown: https://uql-orm.dev/llms.txt
> The same docs over MCP: https://uql-orm.dev/mcp
> Before writing UQL code, read the skill: https://uql-orm.dev/.well-known/agent-skills/uql-orm/SKILL.md

# SQLite

> Run UQL on SQLite with Node's built-in driver, better-sqlite3, or bun:sqlite.

Source: https://uql-orm.dev/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) |
| `TursoQuerierPool` / `LibsqlQuerierPool` | libSQL / Turso over the wire | see [Turso](https://uql-orm.dev/turso.md) |

If SQLite here is standing in for a Postgres you run in production, [PGlite](https://uql-orm.dev/pglite.md) needs no server either and is actually Postgres.

## No dependency at all

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

```ts
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:

```ts
import { getLoadablePath } from 'sqlite-vec';

const pool = new NodeSqliteQuerierPool('app.db', {
  extensions: [getLoadablePath()],
});
```

## Full-text search

`$text` matches an [FTS5](https://sqlite.org/fts5.html) virtual table, which migrations do not (automatically) create: make it yourself and declare an entity over it, then `$text` and `$sort: { $text }` (ranked by `BM25`) work as on any engine. The same goes for libSQL, Turso and D1, which all have FTS5. See [Full-text search](https://uql-orm.dev/querying/full-text.md).

## When to prefer `better-sqlite3`

`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.

```ts
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.

## Populated relations

A populated to-many is aggregated with `json_group_array`, whose `ORDER BY` needs SQLite 3.44. Turso lacks it, so its rows keep the subquery’s order.

A populated `float` keeps 15 significant digits on SQLite 3.51 and libSQL, 17 on 3.53.
