Skip to content

Remove better-sqlite3; use native node:sqlite (Node) + bun:sqlite (Bun) #668

Description

@vivek7405

Problem

A scaffolded full-stack app depends on better-sqlite3, a NATIVE module. This is undesirable on BOTH runtimes webjs supports:

  • On Node, it compiles via node-gyp (or fetches a prebuilt) at install. That native step is the slowest, most failure-prone part of getting a fresh app to serve (a tail risk on a too-new Node ABI, ARM64, locked-down networks, exactly the bleeding-edge combinations webjs's Node 24+ floor invites).
  • On Bun, it is even worse: the connection switches to bun:sqlite at RUNTIME, so better-sqlite3 is installed but NEVER used, yet package.json still lists it unconditionally and adds trustedDependencies: ['better-sqlite3'] so its native prebuild postinstall runs on bun install. A native dep installed for nothing.

Both runtimes now have a built-in SQLite plus a first-class Drizzle adapter, so better-sqlite3 can be removed entirely:

  • Node 24+ ships built-in node:sqlite (verified flag-free on Node 26: require('node:sqlite') exposes DatabaseSync / StatementSync).
  • Bun ships built-in bun:sqlite.
  • Drizzle ships first-class adapters for both (verified in the installed drizzle-orm@1.0.0-rc.3): drizzle-orm/node-sqlite and drizzle-orm/bun-sqlite, each with the full driver / session / migrator export trio, structurally identical to drizzle-orm/better-sqlite3.

Decision (owner directive)

REMOVE better-sqlite3 completely. Use the native adapter per runtime: node:sqlite + drizzle-orm/node-sqlite on Node, bun:sqlite + drizzle-orm/bun-sqlite on Bun. This is a full removal, not an opt-in fallback. (The earlier conservative "opt-in first" framing is superseded by this directive; the adapter blocker is cleared.)

Implementation notes (for the implementing agent)

  • The connection generator is packages/cli/lib/create.js (the runtime-neutral db/connection.server.ts it emits, around L653-669, currently switches bun:sqlite on Bun vs better-sqlite3 on Node). Change the Node branch to node:sqlite + drizzle-orm/node-sqlite. Note the API shift: better-sqlite3 is new Database(path), node:sqlite is new DatabaseSync(path) (from node:sqlite); use what drizzle-orm/node-sqlite expects as its driver.
  • Dependencies: packages/cli/lib/create.js L353 adds 'better-sqlite3' for the sqlite dialect, and L406 adds trustedDependencies: ['better-sqlite3'] when isBun. Remove both. The sqlite dialect should add NO native driver dependency (both drivers are runtime built-ins; only drizzle-orm remains).
  • Runtime rewrite + Dockerfile: packages/cli/lib/runtime-rewrite.js has Dockerfile copy that references the better-sqlite3 glibc prebuild + trustedDependencies (around L107-146); strip those. The pure oven/bun:1 Dockerfile no longer needs the prebuild note. Check the Node Dockerfile template too.
  • The Node 24 floor flag: node:sqlite is flag-free on Node 26 but may need --experimental-sqlite (and emit an experimental warning) on the Node 24.x floor. The CLI controls the launch flags for webjs dev / start (packages/cli/bin/webjs.js), so inject --experimental-sqlite conditionally on the running Node version when required, and confirm the version floor. Verify on a real Node 24.x, not just the Node 26 in this environment.
  • Migrations: confirm webjs db migrate / seed (drizzle-kit) work against node:sqlite and bun:sqlite. drizzle-kit generation is dialect-based (driver-agnostic); the runner uses the connection. Verify both runtimes.
  • The 4 in-repo apps + examples/blog: they run on Bun (so already bun:sqlite at runtime) but currently list better-sqlite3 in package.json. Remove it from their deps and confirm they still boot + migrate on Bun. Check each app's db/connection.server.ts (some may predate the runtime-neutral generator and hardcode better-sqlite3); migrate them to the runtime-switch connection.
  • Landmines: do NOT leave a dangling better-sqlite3 import anywhere (the dynamic-import Node branch must use node:sqlite); the .server boundary keeps the driver server-only (invariant 1); node:sqlite's API is not 100% identical to better-sqlite3 (statement API, pragma, bigint handling), so the Drizzle adapter is what smooths it, use the adapter not the raw driver; ensure a Node 24.0 user is not broken by a missing flag.
  • Tests + docs: scaffold tests (test/scaffolds/, a freshly-scaffolded app on Node AND Bun passes webjs check + webjs test + webjs db migrate + seed), a connection round-trip on both runtimes (test/bun/* for Bun, packages/server/test or a scaffold test for Node), a counterfactual; update agent-docs/built-ins.md (DB section), the scaffold per-agent rule files (.cursorrules, AGENTS.md, CONVENTIONS.md, .github/copilot-instructions.md, .agents/rules/workflow.md, the Dockerfile) which all currently name better-sqlite3 as "the DB driver", and the docs-site DB page.

Acceptance criteria

  • better-sqlite3 appears nowhere: not in any scaffold package.json, not in trustedDependencies, not in any db/connection.server.ts, not in the Dockerfiles, not in the 4 in-repo apps' deps.
  • A freshly-scaffolded sqlite app serves + runs webjs db migrate / seed on Node (via node:sqlite + drizzle-orm/node-sqlite) with NO native module install.
  • The same on Bun (via bun:sqlite + drizzle-orm/bun-sqlite).
  • A Node 24.x floor user is not broken (the --experimental-sqlite flag injected by the CLI if required; verified on real Node 24, not only Node 26).
  • The 4 in-repo apps boot + migrate on Bun with better-sqlite3 removed from their deps.
  • Tests cover both runtimes (scaffold + migrate + round-trip), with a counterfactual.
  • Docs + all scaffold per-agent rule files + the Dockerfile no longer reference better-sqlite3.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

  • Status
    Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions