Database

Code generation

Generate typed database imports and browser functions from your schema.

On this page

Run hulla-db generate to create typed imports from your schema and function declarations. Server code gets database builders, and browser code gets functions it can call without importing server handlers.

Generation requires Bun and TypeScript 7.0.2. If they aren’t installed yet, follow installation.

Terminal
bun --bun hulla-db generate

A successful run prints Generated database entrypoints. By default, it reads db.config.ts, loads db/schema.ts, and discovers query and mutation declarations beside the schema.

On a first run with no declarations, it creates the constructors you’ll use to write them.

Choose the module for where the importing file runs. These paths start at the project root; adjust them from nested files.

You want toImport
Declare queries and mutations./db/_generated/functions
Read or write directly on the server./db/_generated/server
Call functions from db/tasks.ts in a browser./db/_generated/client/tasks
Configure browser auth and connection settings./db/_generated/client/runtime
Refer to tables and fields./db/_generated/tables
Type rows, inserts, patches, and IDs./db/_generated/types

Browser modules contain calling code and contracts. They do not ship server handlers to the browser. Generated worker files are service artifacts, not application entrypoints.

When to use a package import

Use @hulla/db/schema to define storage and @hulla/db/config for connection and service settings. The package root supplies shared helpers such as Input, Output, and DatabaseError.

For schema-typed query and mutation constructors, import _generated/functions instead of the package root.

Export a query(...) or mutation(...) declaration to make it callable. Ordinary exported functions remain helpers, even when a declaration imports them. Declarations derived with .extend(...) are discovered too.

Nested modules keep their relative paths:

text
db/tasks.ts         → db/_generated/client/tasks.ts
db/admin/reports.ts → db/_generated/client/admin/reports.ts

You don’t need a manual function registry or another api.ts file. Keep the schema, config, helpers, and generated files out of blanket declaration re-exports.

Use a different source directory

Only set functions when discovery needs to start somewhere other than beside the schema:

db.config.ts
import { defineConfig } from '@hulla/db/config'

export default defineConfig({
  database: {
    server: { url: process.env.DATABASE_URL! },
    client: { url: 'http://localhost:3001', credentials: 'include' },
  },
  schema: 'data/schema.ts',
  functions: 'data/functions',
})

Paths resolve relative to the config. Generated output stays beside the resolved schema in _generated/.

Terminal
bun --bun hulla-db dev

The watcher regenerates code and restarts the service when source files change.

Generation does not provision tables

Run init explicitly to provision storage. The watcher does not erase existing data; an incompatible development schema needs an explicit recreation of disposable data.

Generation evaluates your trusted schema and declaration modules. Keep database calls and request-specific work inside handlers, rather than at module initialization. Unsupported handler imports produce a diagnostic.

Generate during your build:

Terminal
bun --bun hulla-db generate

Then start the service from the prepared artifacts:

Terminal
node node_modules/@hulla/db/dist/cli.js serve

serve loads the existing output under Node. It does not run generation or start a watcher. Deploy the config, schema, generated files, runtime dependencies, and native assets together.

Generated files have ownership headers. Keep application code outside _generated/ and leave generated files unedited; the generator protects authored files and removes only its own obsolete output.

See the reference for lower-level generation APIs. Most applications only need the commands on this page.