Browse documentation

Configuration

The shape of flowpanel.config.ts and the options it accepts.

The flowpanel config is a single defineAdmin({...}) call that returns a ResolvedAdminConfig. Everything the admin renders, every behavior it allows, every connection it makes — all of it lives here.

Shape

import { defineAdmin, resource } from "@flowpanel/kit";
import { drizzleAdapter } from "@flowpanel/kit/drizzle";
import { db } from "@/server/lib/db";
import * as schema from "@/server/lib/db/schema";
import { getSession } from "@/server/lib/auth";

declare module "@flowpanel/core" {
  interface FlowpanelTypes {
    db: typeof db;
  }
}

export default defineAdmin({
  adapter: drizzleAdapter({ db, schema }),
  auth: {
    session: getSession,
    role: (s) => (s as { user?: { role?: string } } | null)?.user?.role ?? "guest",
    requireRole: "admin",
  },
  resources: [
    resource(schema.users, { columns: ["email", "role"] }),
  ],
});

Top-level options

OptionTypeDescription
adapterAdapterData source plug-in. drizzleAdapter, prismaAdapter, or your own.
authAuthConfigSession loader + role function (required).
resourcesResourceConfig[]?The list of CRUD surfaces to expose.
dashboardsDashboardConfig[]?Custom dashboard pages at /admin/<path>.
queuesQueueConfig[]?BullMQ queues to surface in the admin nav.
themeThemeConfig?Brand, accent, CSS vars, and theme.components slot overrides.
shellShellConfig | ShellMode?"sidebar" (default), "tabs", or "bare".
labelsLabelsConfig?i18n strings for the built-in chrome.
realtimeRealtimeConfig?{ driver: "memory" } for dev, Redis for prod.
auditAuditConfig?Mutation audit log sink + retention.
rateLimitRateLimitConfig?Per-user or per-IP throttling.
commandPaletteCommandPaletteConfig?Extra ⌘K entries.
scope(ctx) => Scope?Multi-tenant query scoping.
hooks{ onError? }?Request lifecycle hooks.

The route mount point is fixed: app/admin/[[...slug]]/page.tsx for the UI and app/api/flowpanel/[...route]/route.ts for actions. To embed the admin under a different URL, mount Flowpanel(config) at that path and adjust the API base via your project's routing.

Full type signatures live on the Reference / defineAdmin page.

Typing your ctx.db

Augment FlowpanelTypes["db"] once with typeof db and every WidgetContext (the ctx passed to widget queries and row-action run callbacks) gets the typed client automatically — no per-callsite annotations.

declare module "@flowpanel/core" {
  interface FlowpanelTypes {
    db: typeof db;
  }
}

Prisma users can also augment models to recover row inference for resource("User", ...):

import type { User, Post } from "@prisma/client";
declare module "@flowpanel/core" {
  interface FlowpanelTypes {
    db: typeof prisma;
    models: { User: User; Post: Post };
  }
}

Reload behavior

In development, edits to flowpanel.config.ts hot-reload like any other TypeScript module. In production, the config is bundled into the route handler at build time — no runtime config parsing.