Switchboard is a Next.js, Prisma, and TypeScript project for generating
database-backed admin resources and routes from a Prisma schema. The CLI is
published as
@lanebucher/switchboard.
From an existing Next.js App Router and Prisma project:
npm install -D @lanebucher/switchboard@beta
npx switchboard init
npx switchboard generate --pages
npx switchboard auth seed-admin
npm run devBeta warning: Switchboard is in early beta. Test it in a branch first and use
--dry-runbefore writing generated files. Change any default admin credentials in the host project before deploying to production.
Before generation, configure Prisma normally. For SQLite:
DATABASE_URL="file:./dev.db"
SWITCHBOARD_SESSION_SECRET="replace-with-at-least-32-random-characters"Create the database and generate the Prisma client:
npx prisma migrate dev --schema src/prisma/schema.prisma
npx prisma generate --schema src/prisma/schema.prismaOpen http://localhost:3000/admin and sign in with admin / password.
Those credentials are only for local bootstrap. Change the password before
production with switchboard auth seed-admin --admin-password <password>.
init supports projects using either src/app or root app and detects the
standard Prisma schema locations. A matching @/* path alias is used when
available; otherwise generated files use relative imports.
examples/basic-next-prisma is a standalone
Next.js, Prisma, SQLite, and TypeScript app that uses the local CLI package the
same way an outside project would.
Run its complete install, migration, generation, and production build check:
npm run example:smokeRequirements:
- Node.js 20.9.0 or newer
- npm
Set up the repository:
git clone https://github.com/black-candle-technologies/switchboard.git
cd switchboard
npm installCreate the local environment file:
cp .env.example .envOn PowerShell, use:
Copy-Item .env.example .envThe SQLite connection must be:
DATABASE_URL="file:./dev.db"Prisma resolves that path relative to src/prisma/schema.prisma, so the local
database is created at src/prisma/dev.db.
Initialize and seed the database, then start the app:
npm run db:migrate
npm run db:seed
npm run devOpen http://localhost:3000/admin. The generated resource routes are under
/admin/<resource>, for example /admin/users.
Link the CLI from this repository:
cd packages/cli
npm install
npm linkThen run it from the root of a compatible Next.js project:
switchboard init
switchboard generate --pagesTo test the published package without linking it globally:
npx @lanebucher/switchboard generate --pagesswitchboard init [options]| Option | Description |
|---|---|
--schema <path> |
Use a custom Prisma schema path. |
--app-dir <path> |
Use a custom App Router directory. |
--force |
Overwrite existing Switchboard support files whose contents differ. |
--dry-run |
Print detected paths and planned actions without writing files. |
By default, init preserves existing files. It creates the Prisma helper,
Switchboard types/registry/overrides, form and table components, and the admin
layout/index. It also creates app/admin/switchboard.css, a small
framework-free stylesheet that can be edited or replaced. It supports both
src-based and root-based projects. Authentication is generated by default.
The Prisma schema must contain a User model with one scalar @id, a unique
String username or email, a String passwordHash or password, and an enum
role whose enum includes ADMIN. Switchboard reports missing fields and does
not modify the schema.
Set SWITCHBOARD_SESSION_SECRET to a random value of at least 32 characters.
If a project already has middleware.ts, init refuses to claim /admin is
protected unless the generated guard is integrated or --force explicitly
replaces that file.
npx switchboard auth seed-admin
npx switchboard auth seed-admin \
--admin-username admin \
--admin-password "use-a-strong-password"The command creates or resets an administrator using a salted Node scrypt
hash. The default admin / password credentials are insecure and intended
only for local development. --dry-run checks the schema and database record
without writing. Password fields generated in User forms are hashed and never
shown in resource lists.
The generator prefers src/prisma/schema.prisma and src/app, then falls back
to prisma/schema.prisma and root app. Switchboard output defaults to
src/switchboard or root switchboard to match the detected layout.
It reads @/* mappings from tsconfig.json or jsconfig.json; projects
without a usable alias receive relative imports automatically. Use
--schema and --app-dir to override detection.
switchboard generate [options]| Option | Description |
|---|---|
-m, --model <name> |
Generate only one Prisma model. |
--schema <path> |
Schema path relative to the project root. |
--out <path> |
Switchboard output root inside the detected source root. |
--app-dir <path> |
Use a custom App Router directory. |
--pages |
Also generate App Router admin pages. |
--force |
Overwrite existing resource configs and admin page files. |
--dry-run |
Print detected paths and planned actions without writing files. |
Example with custom paths:
npx switchboard generate \
--schema prisma/schema.prisma \
--out src/admin-kit \
--pagesUse --dry-run before generation to inspect every Would create,
Would update, Would skip, or Would overwrite action. Dry-run creates no
files or directories. Use --force only when existing generated configs or
admin pages should be replaced.
--out changes the resource and registry location. Admin pages remain under
the detected App Router directory’s admin folder.
init creates:
src/lib/prisma.ts
src/switchboard/types.ts
src/switchboard/registry.ts
src/switchboard/overrides.ts
src/switchboard/auth.ts
src/switchboard/auth-actions.ts
src/components/form/SmartForm.tsx
src/components/form/DeleteButton.tsx
src/components/table/SimpleTable.tsx
src/middleware.ts
src/app/admin/switchboard.css
src/app/admin/layout.tsx
src/app/admin/page.tsx
src/app/admin/login/page.tsx
Root app projects receive the same structure without the src/ prefix.
generate writes:
src/switchboard/generated/<Model>Resource.ts
src/switchboard/registry.ts
With --pages, it also writes:
src/app/admin/page.tsx
src/app/admin/layout.tsx
src/app/admin/<models>/page.tsx
src/app/admin/<models>/new/page.tsx
src/app/admin/<models>/[id]/edit/page.tsx
Generated resource configs and admin pages belong to the project and can be
edited. Re-running generation reports matching files as unchanged and skips
differing files by default. --force overwrites those files. init follows
the same protection rule for support files.
The generated registry is maintained automatically when Switchboard recognizes
its marker or the initial empty registry created by init. A custom or
ambiguous registry is skipped unless --force is used.
Use --model to limit generation to one Prisma model:
npx @lanebucher/switchboard generate --model User --pagesGenerated forms currently map Prisma fields as follows:
| Prisma field | Generated control |
|---|---|
String |
Text input, with email/password/long-text heuristics |
Int, Float, Decimal, BigInt |
Number input |
Boolean |
Checkbox; optional booleans use a Yes/No/Not set select |
| Enum | Select using the schema enum values |
DateTime |
datetime-local input |
Json |
Multiline JSON textarea |
| Optional scalar | Blank values become null |
| Scalar with a default | Blank values allow Prisma to apply the default |
List pages format dates, booleans, JSON, and null values, validate search/sort query parameters against generated field allowlists, clamp pagination to valid pages, and show distinct empty states for an empty resource and an empty search.
For a relation such as
author User @relation(fields: [authorId], references: [id]), Switchboard
renders authorId as a select. Options use the referenced key as the value and
prefer name, title, label, email, or username as the display field.
List pages include that display field instead of showing only the raw foreign
key.
Generated create, update, and delete actions report common Prisma unique, foreign-key, and missing-record errors in the page. Failed form submissions remain on the form so browser-entered values are retained.
Current runtime limitations:
- Relations support selecting an existing related record only.
- Nested create/update, many-to-many editors, scalar lists, and compound IDs are not generated.
- Relation option lists are loaded in full; autocomplete and remote lookup are not generated yet.
Bytesfields do not receive a specialized upload control.- Generated validation is browser validation plus Prisma/server errors; domain validation remains application code.
| Command | Description |
|---|---|
npm run dev |
Start the local Next.js app. |
npm run lint |
Run ESLint. |
npm run build |
Create a production build. |
npm run db:generate |
Generate the Prisma client. |
npm run db:migrate |
Apply local Prisma migrations. |
npm run db:seed |
Seed the local SQLite database. |
MIT