Skip to main content

SQLite (native)

@sqb/sqlite is the SQB adapter for embedded SQLite, built on the runtime's own native SQLite bindings — node:sqlite on Node.js, bun:sqlite on Bun — so it needs no native build step and no separate driver package to install.

warning

@sqb/sqlite requires Node.js >= 22.5 (or Bun), stricter than the rest of the project's >= 20.0 requirement, because node:sqlite isn't available on older Node.js versions. If you need to support older Node.js runtimes, or a browser/non-native environment, use @sqb/sqljs instead.

Install​

npm install @sqb/sqlite

@sqb/connect and @sqb/builder are peer dependencies pulled in transitively if you already depend on them directly; otherwise install them alongside.

Registering the adapter​

Importing @sqb/sqlite registers it as a side effect — there's nothing else to wire up:

import '@sqb/sqlite';
import { SqbClient } from '@sqb/connect';

const client = new SqbClient({
dialect: 'sqlite', // or driver: 'sqlite'
database: './mydb.sqlite',
});

Under the hood, @sqb/sqlite's entry point imports @sqb/sqlite-dialect (shared with @sqb/sqljs — both generate standard SQLite SQL) and registers a SqliteAdapter instance with AdapterRegistry. SqliteAdapter reports driver: 'sqlite' and dialect: 'sqlite'.

At runtime, the adapter detects whether it's running under Bun (globalThis.Bun present) or Node.js and dynamically imports the matching driver module (bun:sqlite or node:sqlite) accordingly — no configuration is needed to pick one.

Configuration​

database is required — the adapter throws if it's missing. It's resolved as an absolute file path, except for the special value :memory: (optionally suffixed, e.g. :memory:mydb), which opens an in-memory database instead:

new SqbClient({ dialect: 'sqlite', database: ':memory:' });

There is no driverOptions passthrough for this adapter — only database is used to open the connection.

Connection sharing​

Multiple SqbClient/pool connections opened against the same non-memory database path share a single underlying native database handle (reference-counted, closed once the last connection to it closes), so concurrent connections to the same SQLite file don't each open a separate native handle.

Feature notes​

  • Cursors: supported (features.cursor: true) — see Cursors & Streaming.
  • Schemas: not supported — SQLite has no server-side schema concept.
  • RETURNING: SQLite supports INSERT/UPDATE/DELETE ... RETURNING natively via the dialect, but the adapter still emulates it with a follow-up SELECT (matched via rowid for inserts, or the original WHERE clause for updates) rather than relying on it. Only the parameters that re-SELECT actually references are passed to it (fixed in v6.2.0 — earlier releases failed on UPDATE ... RETURNING once a SET value was bound as a parameter, because node:sqlite rejects unknown named parameters).
  • Full-text search: the Match operator renders as an FTS5 MATCH (since v6.1.0) — see @sqb/sqlite-dialect.
  • Statements without a result set (DDL, PRAGMA, INSERT OR REPLACE, ...) are run with the driver's run() rather than a lazy iterator, and rowsAffected is reported for INSERT/REPLACE/UPDATE/DELETE (fixed in v6.1.0 — earlier releases silently skipped such statements when executed through client.execute()).

Migrator support​

Supported since v6.0.8 — see Running migrations. SqliteMigrationAdapter is selected by connection.dialect: 'sqlite' (with driver unset or 'sqlite'; driver: 'sqljs' selects the sql.js adapter instead). SQLite has no schema object, so infoSchema is only a table-name prefix and $(schema) resolves to main, SQLite's always-present default database name. A whole multi-statement script runs in one call, and locking is a no-op — SQLite is embedded and single-process, with no server to arbitrate a lock between clients. SQLite runs DDL inside transactions, so it supports transaction: 'run'/'migration' and dryRun (since v6.3.0 — see Transactional runs).

See also​