Drizzle setup
Connect FlowPanel to an existing Drizzle ORM project.
The Drizzle adapter uses your schema objects for row types and introspection, then executes resource operations through your existing database client.
Requirements
Install and configure Drizzle before adding FlowPanel. The supported package range appears in Getting started. PostgreSQL, MySQL, and SQLite dialects are supported.
The adapter is included in @flowpanel/kit; import it from @flowpanel/kit/drizzle.
Configure the adapter
import { defineAdmin, resource } from "@flowpanel/kit";
import { drizzleAdapter } from "@flowpanel/kit/drizzle";
import { getSession } from "@/server/lib/auth";
import { db } from "@/server/lib/db";
import * as schema from "@/server/lib/db/schema";
export default defineAdmin({
adapter: drizzleAdapter({ db, schema }),
auth: {
session: getSession,
role: (session) => (session as { user?: { role?: string } } | null)?.user?.role ?? "guest",
requireRole: "admin",
},
resources: [
resource(schema.users, {
columns: ["email", "name", "role", "createdAt"],
search: ["email", "name"],
defaultSort: { field: "createdAt", dir: "desc" },
}),
],
});
Pass the same db and schema namespace used by the application. The adapter normally infers the dialect from a table in schema; set dialect explicitly only when the schema object contains no detectable Drizzle table.
resource(schema.users, …) infers its row from $inferSelect. Column names, search fields, filters, form fields, action rows, and renderers use that type. The FlowpanelTypes.db augmentation gives dashboard and action contexts the type of your real client.
Database behavior
Search and filter expressions are dialect-aware. Pagination is offset-based. A configured soft-delete field is set instead of removing the row; normal lists exclude non-null deleted values and can expose a restore workflow.
FlowPanel's initial migration is PostgreSQL SQL. Review and adapt it before applying it to MySQL or SQLite.
Limitation
Automatic introspection covers scalar table columns returned by Drizzle. Relations declared with relations() are not turned into joined list values. Use a reference field, a custom column renderer, or a custom adapter when a view needs joined data.
Continue with Getting started or see the generated Adapter reference.