The admin panel
for JavaScript ORMs.
Register models, keep your auth, and get a guarded admin from the schema you already have.
It mounts on the stack you already run.
PanelJS does not replace your app. You keep the HTTP server, the ORM, and your auth. The packages read the schema and serve the panel.
Expressmount(app, admin)
Prismaschema.prisma
TypeORMDataSource
MikroORMMikroORM instance
TypeScripttyped register()
Bun or NodeNode 20+ / Bun 1.3
- No second schema to maintain
- No built-in login to rip out later
- Scope applied on every query
Built from the schema. Guarded by your auth.
You register models. At mount, PanelJS introspects your Prisma schema, TypeORM entities, or MikroORM metadata and serves a React admin at /admin plus a JSON API at /admin/api/*.
Learn how to get started, register models, and configure authentication.
Schema is the source of truth
admin.register("User")with no extra config still produces a list, search, filters, and a create/edit form.Built-in or your own auth
Use the admin-only login, or map an existing session onto
getCurrentUser. If that returns null, the API is 401.Permissions and tenant scope
Role checks decide the verb.
scope()decides the rows. Same role does not mean the same records.Operations the team can use today
Search, filters, pagination, relation display fields, and custom actions on selected list records.
Three calls. Everything else is optional.
- createAdmin
Pass a Prisma, TypeORM, or MikroORM adapter, plus auth. The library never ships a development backdoor.
- register
Choose the models operators may touch. Add list columns, permissions, or actions only when you need them.
- mount
Attach the UI and API to your Express app. Fastify and Nest are next. Deploy wherever that app already runs.
One command. Then mount.
init asks for your framework and ORM, then installs the packages. It does not rewrite your source. Paste createAdmin next to the server you already have.
- Express 4 and 5 today. Fastify and Nest next.
- Prisma 7.5.x, TypeORM 0.3, or MikroORM 6.4+
- Node 20.19+ or Bun 1.3+
pnpm dlx paneljs@latest initimport express from "express"
import { createAdmin } from "paneljs"
import { prismaAdapter } from "@paneljs/prisma"
import { mount } from "@paneljs/express"
import { prisma } from "./prisma.js"
const app = express()
const admin = createAdmin({
adapter: prismaAdapter({ prisma }),
auth: { getCurrentUser },
})
admin
.register("User")
.register("Post", { listDisplay: ["title", "published"] })
await mount(app, admin)
app.listen(3000)Your operators deserve better than a custom dashboard.
Init, register your models, and let the schema do the rest.
