Skip to content

D1

Source: src/Drizzle/D1.ts

Open a Drizzle database over a Cloudflare D1 binding using the drizzle-orm/effect-d1 integration (which drives queries through @effect/sql-d1’s D1Client).

Accepts the client returned by Cloudflare.D1.QueryDatabase(db) — or its raw effect directly — and returns a chainable Proxy over EffectSQLiteD1Database (via proxyChain): every property read records a step, every call records args, and the chain is replayed against the resolved drizzle db when it’s finally yielded as an Effect. Callers don’t need a separate yield* conn step:

const d1 = yield* Cloudflare.D1.QueryDatabase(Db);
const db = yield* Drizzle.D1(d1, { relations });
fetch: Effect.gen(function* () {
const rows = yield* db.select().from(users);
});

The client build is deferred until the first query and memoized on the current execution’s Scope (via makeExecutionMemo), so the D1Client (and its prepared-statement cache) is built at most once per execution — a Worker fetch/queue/scheduled event, a Durable Object call, or a Workflow run — and reused across every query in that execution. Resolving the binding is likewise deferred, so deploy / plan-time invocations (where WorkerEnvironment isn’t provided) never touch D1.

The client is built against that same execution scope, so its finalizer fires when the scope closes — when the request / run settles, not when the Worker’s isolate-lifetime init completes. Wrapping queries in a nested Effect.scoped narrows both the memo and the client’s lifetime to that block: memo key and finalizer target are always the same scope object, so they cannot disagree.