Register a model
admin.register("User");
admin.register("Post", { listDisplay: ["title", "author", "published"] });The first argument is the model or entity name in your ORM — PascalCase, exact. The second argument is optional. Every key on it is optional.
register is synchronous. It stores intent. Validation and default-filling happen in mount.
Zero config
admin.register("User") still works. At mount the library picks:
| Concern | Default |
|---|---|
| Display label | First unique string among name, title, label, username, slug, email; else any unique string; else first string; else the id |
| List columns | Display field first, then other non-id scalars, up to 6, then createdAt if present |
| Search | Non-id string scalars (not FK scalars) |
| Filters | None — configure listFilter explicitly |
| Sort | createdAt descending, or the id |
| Page size | 50 |
| Permissions | Any authenticated admin |
| URL slug | Simple English plural (User → users, Category → categories) |
Reach for the second argument when those defaults are wrong — not before.
The step-by-step for putting this in your server file is Wire it into your app. That page walks through the same register() object as the published example.
What you can customize
admin.register("Post", {
listDisplay: ["title", "author", "published", "createdAt"],
listFilter: ["published", "createdAt"],
searchFields: ["title", "content"],
defaultSort: { field: "createdAt", direction: "desc" },
perPage: 25,
displayField: "title",
pluralName: "posts",
fields: {
content: { readOnly: true },
},
permissions: {
delete: ["SUPER_ADMIN"],
},
scope: async (adminUser) =>
adminUser.isSuperAdmin
? {}
: { tenantId: adminUser.tenantId ?? "__no_tenant__" },
});Full table: register() reference.
Validation at mount
These throw with the available names so a typo does not become a silent empty column:
- Model does not exist in the adapter’s introspected models
listDisplay/fields/displayFieldnames that are not on the modelsearchFieldsthat are not stringslistFilterfields that are not filterableregister()aftermount()mount()twice
Composite primary keys and models with no id are skipped with a warning across all adapters. They cannot be registered in this release.
Only registered models appear
A model in the schema is invisible to the admin until you register it. The Prisma example has Tenant and AdminAuditLog in the schema and never registers them — so they never show in the sidebar.