d1zzle — Cloudflare D1 専用の型安全 ORM(OSS)
Drizzle の書き味そのままに、Cloudflare D1 と Workers だけを対象に作り直した ORM。バンドルサイズを minified で 43% 削減しました。
- 担当範囲
- 設計・実装・メンテナンス(個人 OSS)
- 期間
- 開発・公開中
- 技術スタック
- TypeScript Cloudflare D1 Cloudflare Workers vitest
- Drizzle 互換のスキーマ DSL・クエリビルダ・型推論
- Worker バンドル 77.8kB → 44.1kB(minified、−43%)
- D1 の位置指定リードパス・バインドパラメータ上限・Sessions API に最適化
- Better Auth 向けのネイティブアダプタを同梱
なぜ自作したのか
Cloudflare D1 で開発していると、汎用 ORM の「他のデータベースにも対応するための層」が そのまま Worker のバンドルに乗ってきます。方言(dialect)の間接層、トランザクションと セーブポイントのサブシステム、同期ドライバと非同期ドライバの両方を覆う prepared statement の抽象 — これらは SQLite のエントリポイントから到達可能なため、どんな バンドラでも tree-shaking では落とせません。tree-shaking が消せるのは到達不能な コードであって、汎用的なコードではないからです。
d1zzle は、それをソースの時点で取り除いたライブラリです。API は Drizzle から そのまま受け継いでいるので、既存の知識で書けます。
import { drizzle, eq, integer, sqliteTable, text } from 'd1zzle';
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
email: text('email').notNull().unique(),
name: text('name'),
});
const db = drizzle(env.DB);
const one = await db.select().from(users).where(eq(users.id, 1)).get();
効果
ドライバ・スキーマ DSL・1 本の select().from().where() を含む Worker を esbuild で
バンドルした比較です。
| minified | gzipped | |
|---|---|---|
drizzle-orm/d1 + drizzle-orm/sqlite-core | 77.8 kB | 22.2 kB |
d1zzle | 44.1 kB | 15.3 kB |
| −43% | −31% |
対象を 1 つに絞ると、削れるものが増えるだけでなく、他のデータベースに対応物がない D1 固有の機能を第一級で扱えるようになります。D1 の位置指定リードパス、 バインドパラメータの上限、Sessions API、課金カウンタといった要素が、抽象化の 向こう側ではなく API の表面に出てきます。
実プロダクトでの利用
d1zzle は「作って公開して終わり」のライブラリではなく、あるくとまるの
本番環境で全面採用しています。認証基盤の Better Auth も、d1zzle のネイティブ
アダプタ(d1zzle/better-auth)経由で同じ ORM の上に乗せています。使いながら
見つかった癖は利用側リポジトリのノートに書き出し、ライブラリ本体の改善に戻す
サイクルで運用しています。