UNPKG

drizzle-orm-node-sqlite

Version:
290 lines (182 loc) 10.4 kB
# drizzle-orm-node-sqlite A tiny adapter that lets **Drizzle ORM** talk to Node’s built-in **`node:sqlite`** - no extra native modules. It works anywhere Node runs (Node/Electron main or preload). It’s not a browser driver. Under the hood this uses Drizzle’s **SQLite Proxy** driver: Drizzle builds SQL + parameters and calls our executor; we execute with `node:sqlite` and return rows in the shape Drizzle expects. Drizzle’s proxy contract requires **array-shaped rows** for `all/get/values` - this adapter ensures that, including on older Node versions. ([orm.drizzle.team](https://orm.drizzle.team/docs/connect-drizzle-proxy "Drizzle ORM - Drizzle Proxy")) ---------- ## Requirements - **Node.js ≥ 22.5.0** (when `node:sqlite` was introduced; stability “Active development”). ([nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) - **Drizzle ORM ≥ 0.44.0** (tested up to 0.44.x). > **Node 22 vs Node 24** > > - Node 22 returns rows as **objects**. > > - Node 24+ can return rows as **arrays** via `statement.setReturnArrays(true)` or `new DatabaseSync(path, { returnArrays: true })`. This adapter works either way; if arrays are already returned, it forwards them unchanged. ([nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) > ---------- ## Install ```bash npm i drizzle-orm drizzle-orm-node-sqlite # or: pnpm add / yarn add ``` TypeScript projects should use a modern resolver so TS respects package `exports`: ```jsonc // tsconfig.json { "compilerOptions": { "moduleResolution": "NodeNext", "types": ["node"] } } ``` ---------- ## Quick start ```ts // db.ts import { drizzle } from 'drizzle-orm-node-sqlite' import * as schema from './schema' // your drizzle-orm/sqlite-core tables // If migrating from libsql, normalize "file:*.db" to a file path: const DB_PATH = (process.env.DB_FILE_NAME ?? 'local.db').replace(/^file:/, '') export const db = drizzle({ client: DB_PATH, // or ':memory:' or an existing new DatabaseSync(DB_PATH, { ...options }) schema, // required if you want db.query.<table>.* readBigInts: true // maps INTEGERs to JS bigint (see BigInt section) }) ``` Why pass `schema`? Because Drizzle only creates the `db.query.<table>` helpers when you initialize with your schema. ([orm.drizzle.team](https://orm.drizzle.team/docs/rqb?utm_source=chatgpt.com "Drizzle ORM - Query")) ---------- ## Example ```ts import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core' import { eq } from 'drizzle-orm' import { db } from './db' export const users = sqliteTable('users', { id: integer().primaryKey({ autoIncrement: true }), username: text().notNull(), }) await db.execute(` create table if not exists users( id integer primary key autoincrement, username text not null ) `) await db.insert(users).values({ username: 'ada' }) const first = await db.query.users.findFirst({ where: (t, { eq }) => eq(t.username, 'ada') }) console.log(first) ``` ---------- ## Options you can pass These map to `node:sqlite` statement behaviors and Drizzle proxy ergonomics: ```ts drizzle({ client: 'app.db', // string path or a DatabaseSync instance schema, // enables db.query.* logger: true, // Drizzle logger passthrough readBigInts: true, // StatementSync#setReadBigInts(true) allowBareNamedParameters: true, allowUnknownNamedParameters: false, }) ``` `readBigInts` makes INTEGER reads come back as `bigint` instead of `number`. (Writes accept either.) ([nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) ---------- ## Node 22 vs Node 24 behavior ### Node 22 (v22.x) - `statement.setReturnArrays()` is **not** available; statements return objects. - This adapter converts objects → arrays (in DB column order) to satisfy Drizzle’s proxy contract. ([orm.drizzle.team](https://orm.drizzle.team/docs/connect-drizzle-proxy "Drizzle ORM - Drizzle Proxy")) ### Node 24 (v24.x) - You **can** opt into array rows and skip conversion: ```ts import { DatabaseSync } from 'node:sqlite' const sqlite = new DatabaseSync('app.db', { returnArrays: true, // rows as arrays timeout: 2000 // busy timeout in ms (optional) }) const db = drizzle({ client: sqlite, schema }) ``` `setReturnArrays(enabled)` on `StatementSync` and the `returnArrays` / `timeout` database options were added in v24.x. `DatabaseSync` APIs execute synchronously. ([nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) ---------- ## BigInt & JSON (tRPC, RPCs, HTTP) If you enable `readBigInts: true`, you’ll get JS `bigint` values for large integers. Plain `JSON.stringify` cannot serialize `bigint`, so add a data transformer (e.g. **SuperJSON**) to your API layer. **tRPC (server):** ```ts import { initTRPC } from '@trpc/server' import superjson from 'superjson' export const t = initTRPC.create({ transformer: superjson }) ``` **tRPC (client):** ```ts import { createTRPCClient, httpLink } from '@trpc/client' import superjson from 'superjson' export const client = createTRPCClient({ links: [httpLink({ url, transformer: superjson })] }) ``` tRPC docs: “**Data transformers**” (SuperJSON & others). ([trpc.io](https://trpc.io/docs/server/data-transformers?utm_source=chatgpt.com "Data Transformers - tRPC")) If you don’t need exact precision, set `readBigInts: false` and you’ll get JS numbers instead. ([nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) ---------- ## Migrations (Drizzle Kit) Keep using the SQLite dialect and point Drizzle Kit at the same file path: ```ts // drizzle.config.ts import { defineConfig } from 'drizzle-kit' export default defineConfig({ out: './drizzle', schema: './src/schema.ts', dialect: 'sqlite', dbCredentials: { url: './app.db' } // or your path }) ``` Drizzle Kit reads `dialect` plus `dbCredentials` to run migrations. ([orm.drizzle.team](https://orm.drizzle.team/docs/drizzle-kit-migrate?utm_source=chatgpt.com "Drizzle ORM - `migrate`")) ---------- ## Transactions & batch Drizzle’s proxy driver supports `db.batch([...])` and regular transactions (`BEGIN/COMMIT/ROLLBACK`) - this adapter just executes whatever SQL Drizzle emits. It returns rows as arrays as required by the proxy contract. ([orm.drizzle.team](https://orm.drizzle.team/docs/connect-drizzle-proxy "Drizzle ORM - Drizzle Proxy")) ---------- ## Development To contribute, first set up the development environment: ```bash # Clone the repository git clone https://github.com/your-repo/drizzle-orm-node-sqlite.git cd drizzle-orm-node-sqlite # Install dependencies yarn install ``` The following scripts are available: - `yarn build`: Compiles TypeScript source to JavaScript in the `dist/` directory. - `yarn test`: Builds the project and runs the integration tests. - `yarn lint`: Lints the codebase for style and consistency issues. - `yarn lint:fix`: Automatically fixes fixable linting issues. ---------- ## Performance & concurrency tips - **Synchronous API:** `DatabaseSync` APIs are synchronous; long-running queries can block the event loop. For heavy work, consider moving DB operations to a **Worker Thread** or a simple job queue. ([nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) - **WAL mode:** For multi-reader/mixed workloads, enabling **Write-Ahead Logging** often improves concurrency (readers don’t block writers and vice-versa). Do this once at startup: ```ts sqlite.exec(`PRAGMA journal_mode = WAL;`) ``` (See SQLite’s WAL docs for trade-offs.) ([www3.sqlite.org](https://www3.sqlite.org/wal.html?utm_source=chatgpt.com "Write-Ahead Logging - SQLite")) - **Busy timeout (Node 24+):** You can set `timeout` in `new DatabaseSync(path, { timeout: 2000 })` to reduce `SQLITE_BUSY` errors under contention. ([nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) ---------- ## Electron notes Use this in the **main process** or a **preload** (with Node APIs exposed). If your renderer is sandboxed (no Node APIs), call into the main process via IPC. `node:sqlite` is a Node builtin (available via the `node:` scheme), not a web API. ([nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) ---------- ## FAQ **Q: Is this browser-compatible?** A: No. `node:sqlite` runs in Node. For browsers, use an HTTP proxy driver or a WASM SQLite build. Drizzle’s proxy docs cover how to return array rows from a HTTP service. ([orm.drizzle.team](https://orm.drizzle.team/docs/connect-drizzle-proxy "Drizzle ORM - Drizzle Proxy")) **Q: Do I have to pass `schema`?** A: Only if you want the `db.query.<table>` helpers. Without it, use the regular query builder `db.select().from(t)` etc. ([orm.drizzle.team](https://orm.drizzle.team/docs/rqb?utm_source=chatgpt.com "Drizzle ORM - Query")) **Q: What about `COUNT(*)` returning `bigint`?** A: With `readBigInts: true`, counts may be `bigint`. Serialize via a transformer (e.g., SuperJSON), or cast to `TEXT`/`REAL` in SQL if you must return plain JSON. ([trpc.io](https://trpc.io/docs/server/data-transformers?utm_source=chatgpt.com "Data Transformers - tRPC")) ---------- ## How it works (brief) - Drizzle’s **SQLite Proxy** driver calls a function with `(sql, params, method)` and expects array rows back. - We prepare a `StatementSync`, apply toggles like `setReadBigInts`, execute, and return **arrays**. On Node 24+, if arrays are already enabled (`returnArrays`/`setReturnArrays`), we skip the object→array conversion. ([orm.drizzle.team](https://orm.drizzle.team/docs/connect-drizzle-proxy "Drizzle ORM - Drizzle Proxy"), [nodejs.org](https://nodejs.org/api/sqlite.html "SQLite | Node.js v24.6.0 Documentation")) ---------- ## Minimal API surface ```ts type Config<TSchema = unknown> = { client?: string | DatabaseSync databaseOptions?: ConstructorParameters<typeof DatabaseSync>[1] schema?: TSchema logger?: boolean readBigInts?: boolean allowBareNamedParameters?: boolean allowUnknownNamedParameters?: boolean } ```