@bezoar/nuxt

Nuxt module for bezoar: a typed database service for server routes, from a kit build
779
Install
npm install @bezoar/nuxt
Latest Version:0.0.5
Vue:3
License:MIT
Last Updated:Oct 23, 2026
Links: GitHub  ·  npm
Maintainer: zoobzio

@bezoar/nuxt

Nuxt module for bezoar. The module takes a kit build and gives the server a typed database service.

Install

pnpm add @bezoar/nuxt

Setup

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@bezoar/nuxt"],
  bezoar: { build: "@acme/database", migrate: true },
});

build names a kit build: a package whose main entry is the index.mjs that bezoar build wrote, or a path to that directory. The module adds two virtual modules to the server build: #bezoar/build, which re-exports the modules of the kit build, and #bezoar/service, the service over its contract and its SQL. It writes a declaration of the service into the build directory. useBezoar() and its types come from the virtual service, so they are typed by the build. The modules are virtual so that Nitro bundles them in dev as in production; the server plugin of the module imports both.

Connection

The module reads runtimeConfig.bezoar. An environment variable sets each member.

Member Variable Meaning
url NUXT_BEZOAR_URL The connection string, for the pg driver
dataDir NUXT_BEZOAR_DATA_DIR The data directory, for the pglite driver
driver NUXT_BEZOAR_DRIVER pg or pglite. Defaults to pg
migrate NUXT_BEZOAR_MIGRATE Apply the migrations when the server starts
seed NUXT_BEZOAR_SEED Run the seeds when the server starts
roles NUXT_BEZOAR_ROLES Apply the grants when the server starts
role NUXT_BEZOAR_ROLE The role the service is scoped to

driver, migrate, seed, roles, and role can also be set in the module options. A value in the runtime config wins.

The pg driver connects to a Postgres server and needs url. The pglite driver runs Postgres in the process, on dataDir, or in memory when it is empty. A server with the pg driver and no url fails to start.

In a server route

export default defineEventHandler(async (event) => {
  const db = useBezoar();
  const { day } = await getValidatedQuery(
    event,
    db.schema.validators.queries["events.list"].arguments.parse,
  );
  return db.events.list({ day });
});

useBezoar() is auto-imported on the server. It returns the same service on every call, typed by the contract of the build, so db.events.list completes, and its arguments and rows check. The service carries the query builder of @bezoar/core, db.build, a kysely typed by the tables of the build, so db.build.selectFrom("events") completes as well. AppBezoar, AppBezoarContract, AppBezoarQuery, AppBezoarArguments<Q>, AppBezoarRow<Q>, and AppBezoarDatabase are the types, also auto-imported.

Roles

A build with roles carries, for each role, the queries it may run. role scopes the service of the app to one of them.

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@bezoar/nuxt"],
  bezoar: { build: "@bbf/database", role: "web" },
});

useBezoar() then offers the queries of the role and no other, and its type narrows to them: in the app of web, db.admin.events.update is a type error. The queries run as the role: the pg driver opens a pool of its own that takes the role on each connection, and the pglite driver a second executor over the one database. The login user of the connection string must be a member of the role. In production that user can be a member of the role alone, and the database holds the scope whatever the service does. In development on pglite, the one superuser takes the role, and a query that reaches past it fails on your machine as it would in production.

useBezoarOwner() is the service over every query as the login user, which the plugin runs the startup work on. Without a role, it is useBezoar() itself. AppBezoarRole is the role of the module options, as a type, or undefined.

A login user that is a member of its role alone cannot migrate or grant. An app over one sets migrate, roles, and seed to false, and the owner of the database, another app or a deploy step, applies them.

Startup and shutdown

A server plugin makes the service when the server starts. With roles, it declares the roles of the build first, through roles.declare of @bezoar/core, so a migration can name one. With migrate, it applies the migrations of the build, through migrate, under an advisory lock, so instances that start together apply each migration once. With roles, it then applies the grants, through roles. With seed, it runs the seeds last. The startup work runs on useBezoarOwner(). When the server stops, the plugin closes the connections. closeBezoar() closes them by hand.

Runtime

The pg driver needs a Node runtime, which the Node server presets of Nuxt and the functions of Vercel are.

Related

Version History

Version Released Vue License
0.0.5 ^3.0 MIT
0.0.4 ^3.0 MIT
0.0.3 ^3.0 MIT
0.0.2 ^3.0 MIT
0.0.0 MIT
Pre-releases (1)
Version Released License
0.0.0-stage