Skip to content

ORM adapters

Two thin packages wrap @persql/sdk so you can plug PerSQL into the Drizzle or Kysely query builders without writing the proxy yourself.

Terminal window
npm i @persql/sdk @persql/drizzle drizzle-orm
import { drizzle } from "@persql/drizzle";
import { PerSQL } from "@persql/sdk";
import { eq } from "drizzle-orm";
import * as schema from "./schema";
const persql = new PerSQL({ token: process.env.PERSQL_TOKEN! });
const db = drizzle(persql.database("acme/orders"), { schema });
const users = await db
.select()
.from(schema.users)
.where(eq(schema.users.id, 42));

Generate schema.ts from a live database:

Terminal window
npx persql-codegen --token $PERSQL_TOKEN \
--database acme/orders > schema.ts

The wrapper plugs into Drizzle’s sqlite-proxy driver, so every Drizzle feature — query builder, prepared statements, transactions, relations — works without modification.

Terminal window
npm i @persql/sdk @persql/kysely kysely
import { Kysely } from "kysely";
import { PerSQLDialect } from "@persql/kysely";
import { PerSQL } from "@persql/sdk";
interface DB {
users: { id: number; email: string };
orders: { id: number; user_id: number; total: number };
}
const persql = new PerSQL({ token: process.env.PERSQL_TOKEN! });
const db = new Kysely<DB>({
dialect: new PerSQLDialect({ database: persql.database("acme/orders") }),
});
const rows = await db
.selectFrom("users")
.innerJoin("orders", "orders.user_id", "users.id")
.select(["users.email", "orders.total"])
.execute();

Kysely’s db.transaction() is implemented natively: statements between BEGIN and COMMIT are buffered and shipped as one transactional batch, so a transaction is one HTTP round-trip.

The SDK already exposes db.driver() (the Drizzle proxy callback) so you could wire either ORM by hand. The packages just save a few imports and document the integration as an officially-supported surface.