db0
A lightweight, unified SQL connector for Node.js with pluggable drivers for SQLite, PostgreSQL, MySQL, LibSQL, and serverless databases.
Repository Health
Technical Analysis
db0 is a lightweight SQL connector from the UnJS ecosystem that gives JavaScript and TypeScript projects one consistent query API across many different SQL backends. Instead of writing driver-specific code for SQLite, PostgreSQL, MySQL, LibSQL, or a serverless database like Neon, PlanetScale, or Cloudflare D1, developers create a Database instance from a chosen connector and use the same sql tagged-template and exec/prepare methods regardless of the underlying engine.
The library has zero runtime dependencies of its own — each connector dynamically and lazily imports the third-party client it wraps (better-sqlite3, pg, mysql2, @libsql/client, etc.), so consumers only install what they actually use. db0 also exposes a capabilities object per dialect (JSON support, booleans, arrays, dates, UUIDs, transactions) so calling code can branch on what a given backend actually supports, plus an opt-in tracing layer built on Node’s diagnostics_channel for query-level observability. It is designed to be embedded inside frameworks and ORMs rather than compete with them, and ships first-class integrations for Drizzle and Kysely alongside Prisma driver-adapter support.
What You Get
- A single
createDatabase(connector)API withsqltagged templates,exec, andprepare().all/run/getmethods that work identically across every supported backend - Nine built-in connectors covering local SQLite (better-sqlite3, node:sqlite, sqlite3, bun:sqlite), PostgreSQL/MySQL, and serverless providers (Neon, PlanetScale, Cloudflare D1, Cloudflare Hyperdrive)
- Zero runtime dependencies — each connector lazily imports its own third-party client only when actually used, and exposes a
CONNECTOR_DEPENDENCIESdescriptor so frameworks can check or install what’s needed - A
capabilitiesobject per SQL dialect describing support for JSON, booleans, arrays, dates, UUIDs, and transactions, so calling code can adapt to what the active connector supports - Opt-in query tracing via
db0/tracingbuilt on Node’sdiagnostics_channel, emitting start/end/asyncStart/asyncEnd/error events with query text, method, connector, and result - Ready-made integrations for Drizzle ORM and Kysely, plus a Prisma driver adapter, so db0 can sit underneath an existing ORM instead of replacing it
Common Use Cases
- Building a framework or meta-framework (like Nuxt or Nitro) that needs to support several SQL databases behind one internal data-access layer
- Writing an application that must run unmodified against local SQLite in development and a serverless Postgres/MySQL provider in production
- Adding a lightweight query layer to an edge or serverless function (Cloudflare Workers, Vercel Edge) without pulling in a full ORM
- Instrumenting SQL query performance and errors in production using diagnostics_channel-based tracing instead of manual logging
- Providing the underlying driver for a higher-level ORM/query-builder integration (Drizzle, Kysely, Prisma) so the ORM doesn’t need bespoke driver code per database
Under The Hood
Architecture
db0’s core is small and layered: database.ts implements createDatabase(), a thin factory that wraps a supplied Connector (name, dialect, getInstance, exec, prepare, optional dispose) with disposal tracking, capability lookup, and a sql tagged-template helper that parses interpolations via template.ts (sqlTemplate) and decides whether to call .all() (for SELECT/RETURNING statements) or .run() (for everything else). Each connector under src/connectors/ (better-sqlite3, node-sqlite, sqlite3, bun-sqlite, postgresql, mysql2, libsql, neon, planetscale, cloudflare-d1, cloudflare-hyperdrive-mysql/postgresql, pglite) implements the same Connector interface independently, with shared helpers (lazyInstance, importLib, interopDefault, BoundableStatement) centralized in src/connectors/_internal/. src/_connectors.ts aggregates all connector modules and their CONNECTOR_DEPENDENCIES into typed maps consumed by index.ts. A separate src/tracing.ts wraps a Database instance with diagnostics_channel instrumentation without touching the base implementation, so tracing costs nothing when unused. This gives db0 clean separation between the stable public contract (types.ts), the dispatch logic (database.ts), and the swappable per-database implementations (connectors/*) — changing or adding a connector never touches the core.
Tech Stack
db0 is written in strict TypeScript (99.9% of the codebase) targeting Node.js/Bun/Cloudflare Workers runtimes, built with obuild and distributed as ESM-only (.mjs/.d.mts) with per-connector and per-integration subpath exports (db0/connectors/*, db0/integrations/*, db0/tracing). It has no runtime dependencies itself; instead it dynamically imports whichever third-party driver a connector needs (better-sqlite3, pg, mysql2, @libsql/client, @neondatabase/serverless, @planetscale/database, @electric-sql/pglite, @cloudflare/workers-types), keeping install size minimal for consumers who use only one backend. Development tooling includes jiti for TS execution, automd for auto-generated docs/badges, changelogen for releases, and vitest for testing, all under a pnpm workspace shared with the docs/ site.
Code Quality
The project has an extensive test suite under test/, including dedicated files per connector (sqlite3.test.ts, better-sqlite3.test.ts, postgresql.test.ts, postgresql-params.test.ts, mysql2.test.ts, libsql.test.ts, neon.test.ts/neon.unit.test.ts, planetscale.test.ts, pglite.test.ts, node-sqlite.test.ts, bun-test.ts) plus cross-cutting tests for capabilities, connector dependencies, the SQL template parser, and tracing. CI runs lint (Prettier), a tsc --noEmit type-check pass, Prisma client generation, vitest run --coverage, and a separate Bun test target, with coverage reported via Codecov and an autofix workflow for formatting. Naming is consistent across connectors (each exports a default factory function, ConnectorOptions, and CONNECTOR_DEPENDENCIES), and the public API is fully typed via types.ts with JSDoc comments on every exported member.
What Makes It Unique
Rather than being an ORM or query builder, db0 deliberately stays a thin, dependency-free abstraction over raw SQL execution, intended to sit underneath ORMs (it ships integrations for Drizzle and Kysely and a Prisma driver adapter) rather than compete with them. Its capability-aware design — exposing per-dialect feature flags instead of pretending every backend behaves identically — combined with lazy, on-demand loading of third-party drivers and an explicit CONNECTOR_DEPENDENCIES contract, lets frameworks introspect and provision exactly what a configured connector needs without bundling every possible database client.