Drizzle ORM
Cloudflare D1 and Durable Objects
Declare tables with the SQLite package, then connect them to D1 or Durable Objects storage.
Cloudflare has two SQLite databases: D1 and the SQL storage inside a Durable Object. Both use the SQLite package.
npm install @mionjs/drizzle-orm-sqlite-core @mionjs/drizzle-orm @mionjs/run-types
npm install drizzle-orm # only needed to run queries
There is no D1 or Durable Objects package: in Drizzle ORM, drizzle-orm/d1 and drizzle-orm/durable-sqlite are only drivers. The tables come from drizzle-orm/sqlite-core, which @mionjs/drizzle-orm-sqlite-core already covers. You declare a table once and pick a driver where you connect.
Connecting to D1
Pass the binding from your Worker's env to drizzle, and the table through toDrizzle.
import {drizzle} from 'drizzle-orm/d1';
import {eq} from 'drizzle-orm';
import {toDrizzle} from '@mionjs/drizzle-orm-sqlite-core/drizzle';
import {notes, type Note} from './drizzle-proxy-sqlite-example.ts';
// built once
const notesDb = toDrizzle(notes);
// the database binding
interface Env {
DB: Parameters<typeof drizzle>[0];
}
export async function findNote(
env: Env,
id: number
): Promise<Note | undefined> {
const db = drizzle(env.DB);
// the timestamp is already a Date
const [note] = await db.select().from(notesDb).where(eq(notesDb.id, id));
return note;
}
Connecting to Durable Objects
Inside the object, pass its storage to drizzle instead. Everything else is identical.
import {drizzle} from 'drizzle-orm/durable-sqlite';
import type {DrizzleSqliteDODatabase} from 'drizzle-orm/durable-sqlite';
import {toDrizzle} from '@mionjs/drizzle-orm-sqlite-core/drizzle';
import {
notes,
type Note,
type NewNote,
} from './drizzle-proxy-sqlite-example.ts';
const notesDb = toDrizzle(notes);
// storage needed by Drizzle
interface Storage {
sql: {exec(query: string, ...bindings: unknown[]): unknown};
}
export class NotesObject {
private readonly db: DrizzleSqliteDODatabase;
constructor(storage: Storage) {
this.db = drizzle(storage as never);
}
// models, validators and table work across databases
async addNote(note: NewNote): Promise<Note> {
const [row] = await this.db.insert(notesDb).values(note).returning();
return row;
}
}
Features on Cloudflare
It all comes from the table's types, as on any other database:
- routes typed with the inferred models, validated before your handler runs
- a timestamp column that arrives as a real
Date, in both directions, with nothing to convert by hand - mock data and friendly error messages generated from the same models
Serve those routes with @mionjs/platform-cloudflare.