Supabase is a hosted Postgres + auth + storage platform. The official @supabase/supabase-js client is fetch-based, so it runs on every runtime DaloyJS supports, Node.js, Bun, Deno, Cloudflare Workers, and Vercel.
Treat Supabase as a platform client, not a traditional ORM: you are composing PostgREST, auth, storage, and realtime APIs rather than mapping tables through model classes.
Zod validates the request, the handler calls the fetch-based PostgREST client off state.supabase, the destructured error is mapped to problem+json, then the response schema checks the body. The same client runs on Node.js and every edge runtime.
1. Install
ts
pnpm add @supabase/supabase-js
2. Generate database types
Use the Supabase CLI to generate a fully typed schema:
ts
pnpm dlx supabase loginpnpm dlx supabase gen types typescript --project-id <your-ref> --schema public > src/db/supabase.types.ts
3. Create a Supabase plugin
Create a long-lived service-role client for server-to-server calls. For per-request, user-scoped clients (RLS), instantiate inside the handler with the caller's JWT.
ts
// src/db/supabase.tsimport { createClient, SupabaseClient } from "@supabase/supabase-js";import type { App } from "@daloyjs/core";import type { Database } from "./supabase.types";export type Db = SupabaseClient<Database>;export const serviceClient: Db = createClient<Database>( process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!, { auth: { persistSession: false, autoRefreshToken: false } },);export const supabasePlugin = { name: "supabase", register(app: App) { app.decorate("supabase", serviceClient); },};
4. Augment app state types
ts
// src/types/state.d.tsimport type { Db } from "../db/supabase";declare module "@daloyjs/core" { interface AppState { supabase: Db; }}