npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

drizzle-orm-node-sqlite

v0.1.0

Published

Drizzle ORM adapter for Node's built-in node:sqlite

Readme

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)


Requirements

  • Node.js ≥ 22.5.0 (when node:sqlite was introduced; stability “Active development”). (nodejs.org)

  • 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)


Install

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:

// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "NodeNext",
    "types": ["node"]
  }
}

Quick start

// 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)


Example

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:

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)


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)

Node 24 (v24.x)

  • You can opt into array rows and skip conversion:

    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)


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):

import { initTRPC } from '@trpc/server'
import superjson from 'superjson'
export const t = initTRPC.create({ transformer: superjson })

tRPC (client):

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)

If you don’t need exact precision, set readBigInts: false and you’ll get JS numbers instead. (nodejs.org)


Migrations (Drizzle Kit)

Keep using the SQLite dialect and point Drizzle Kit at the same file path:

// 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)


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)


Development

To contribute, first set up the development environment:

# 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)

  • 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:

    sqlite.exec(`PRAGMA journal_mode = WAL;`)
        

    (See SQLite’s WAL docs for trade-offs.) (www3.sqlite.org)

  • Busy timeout (Node 24+): You can set timeout in new DatabaseSync(path, { timeout: 2000 }) to reduce SQLITE_BUSY errors under contention. (nodejs.org)


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)


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)

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)

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)


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, nodejs.org)


Minimal API surface

type Config<TSchema = unknown> = {
  client?: string | DatabaseSync
  databaseOptions?: ConstructorParameters<typeof DatabaseSync>[1]
  schema?: TSchema
  logger?: boolean
  readBigInts?: boolean
  allowBareNamedParameters?: boolean
  allowUnknownNamedParameters?: boolean
}