Entities (Neon)
There are two ways to work with relational (Neon Postgres) data from a PRISM app:
defineEntity— a config-driven admin generator that maps one entity to full CRUD screens, backed by the company-manager tRPC procedures.- Direct Neon access — the framework's
sqltagged template for hand-written queries.
defineEntity
defineEntity lives in the @bext-stack/manage kit, not the framework
(@bext-stack/framework). It is the console/admin surface.
defineEntity maps a single entity to list / detail / new / edit screens plus CRUD,
backed by the company-manager tRPC procedures. It is generic over the tRPC procedure
names — a typo in a procedure name is a compile error.
Transport and configuration
The tRPC transport is cmQuery (GET) / cmMutate (POST), from the kit's cm.ts. Base,
tenant, and site come from configureManage(...), called once as a side-effect import:
import { configureManage } from "@bext-stack/manage";
configureManage({
appId: "<app-id>",
cmBase: "…",
host: "…",
origin: "…",
tenantId: "…",
siteId: "…",
});
| Piece | Role |
|---|---|
configureManage({ appId, cmBase, host, origin, tenantId, siteId }) |
One-time side-effect setup of base/tenant/site. |
cmQuery |
tRPC query transport (GET). |
cmMutate |
tRPC mutation transport (POST). |
Thin re-export pattern
Host a generated entity by re-exporting the kit's entity module from a route file — the route stays a thin shim:
// src/app/manage/posts/page.tsx
export { loader, default } from "@bext-stack/manage/entities/posts";
Example: helpdesk knowledge base
The helpdesk KB entity is a real defineEntity config wired to these procedures:
| Procedure | Use |
|---|---|
helpdeskKb.getArticles |
List articles |
helpdeskKb.getArticleById |
Fetch one article |
helpdeskKb.getCategories |
List categories |
Because defineEntity is generic over these names, renaming or mistyping one is caught at
compile time. See Helpdesk.
Direct Neon access
For hand-written queries the framework exports a tagged-template SQL helper:
import { sql, database, POSTGRES_DIALECT } from "@bext-stack/framework";
const posts = await sql`SELECT id, title FROM posts WHERE tenant_id = ${tenantId}`;
| Export | What it is |
|---|---|
sql |
Tagged-template query helper. |
database |
The database handle. |
POSTGRES_DIALECT |
The Postgres dialect marker. |
The Neon connection string is fetched once via a loopback KV read of the key
cm:database_url, so you do not configure it in the app.
Interpolations in the sql template are parameterized — pass values through ${...} rather
than building query strings by hand.
Where to next
| Page | What it covers |
|---|---|
| Data Model | The tenant-scoped Neon schema and key models |
| Helpdesk | The KB entity in context |
| Loaders & Actions | Where entity reads/writes run |
| KV Store | Where cm:database_url is read from |