Skip to Content
Drizzle ORM & Generator

Drizzle ORM & Generator

@kalamdb/orm is the Drizzle package for KalamDB. Use it when you want generated tables, typed queries, or table-level live helpers. It runs on top of @kalamdb/client.

Install it with the client and Drizzle:

bash snippetBASH
npm i @kalamdb/client @kalamdb/orm drizzle-orm

Driver quick start

Copy this after you have a generated schema.ts file.

ts snippetTS
import { Auth, createClient } from '@kalamdb/client';import { kalamDriver } from '@kalamdb/orm';import { messages } from './schema'; const client = createClient({  url: 'http://localhost:2900',  authProvider: async () => Auth.basic('admin', 'AdminPass123!'),}); const db = kalamDriver(client);const recent = await db.select().from(messages).limit(20);

The driver uses KalamDB SQL over HTTP and normalizes temporal values for Drizzle columns. timestamp(..., { mode: 'date' }), date(..., { mode: 'date' }), and time(...) can read KalamDB’s numeric wire values without app-side parsing.

Table helpers

Use kTable instead of raw pgTable so the schema retains KalamDB table type metadata.

ts snippetTS
import { bytes, embedding, file, kTable } from '@kalamdb/orm';import { bigint, jsonb, text, timestamp, uuid } from 'drizzle-orm/pg-core'; export const docs = kTable.shared('app.docs', {  id: bigint('id', { mode: 'bigint' }).primaryKey(),  owner_id: uuid('owner_id').notNull(),  title: text('title').notNull(),  metadata: jsonb('metadata'),  attachment: file('attachment'),  raw_bytes: bytes('raw_bytes'),  doc_embedding: embedding('doc_embedding', 384),  created_at: timestamp('created_at', { mode: 'date' }).notNull(),});

Available table helpers:

HelperUse for
kTable.shared(name, columns, options?)WITH (TYPE = 'SHARED') tables
kTable.user(name, columns, options?)per-user isolated tables
kTable.stream(name, columns, options?)stream tables
kTable.system(name, columns, options?)system metadata tables
kSystemColumns([...])_seq, _deleted, and _commit_seq typed hidden columns

KalamDB-specific columns:

HelperRuntime value
file(name)`FileRef
bytes(name)`Uint8Array
embedding(name, dimensions)`number[]

Generate schema.ts

Generate a Drizzle schema from a running KalamDB server:

bash snippetBASH
npx kalamdb-orm \  --url http://localhost:2900 \  --user admin \  --password AdminPass123! \  --namespace app \  --include-system-columns \  --out src/db/schema.ts

The generator reads SHOW TABLES, calls DESCRIBE <namespace.table> when column metadata is incomplete, and emits only the imports needed by the generated tables. It preserves primary keys, not-null constraints, system-column options, comments, table config constants such as chat_messagesConfig, and $inferSelect / $inferInsert aliases.

Options:

OptionDescription
--namespace <name>Limit output to one or more namespaces. Repeat it or pass comma-separated names.
--include-systemInclude system and dba tables.
--include-system-columns <mode>Add typed hidden columns to generated table definitions. Use all, _seq, or _deleted.
--bigint-mode <mode>Choose how generated BIGINT columns are emitted. Accepted values are string, bigint, or number; default is string.
--no-type-aliasesSkip generated $inferSelect and $inferInsert aliases.

BIGINT defaults to text() because KalamDB transports Int64 values as strings to preserve precision. Choose --bigint-mode bigint when you want Drizzle to coerce values to native bigint, or --bigint-mode number only when values fit safely in JavaScript numbers.

Keep schema.ts fresh during local development

Add a generator script to your app so the command stays short:

json snippetJSON
{  "scripts": {    "schema:gen": "kalamdb-orm --url http://localhost:2900 --user admin --password AdminPass123! --namespace app --out src/db/schema.ts"  }}

Then let the Kalam CLI rerun that script whenever schema metadata changes:

bash snippetBASH
kalam --watch-schema --namespace app --run "npm run schema:gen" --run-on-start

Repeat --namespace for multiple namespaces, add --table app.messages when you only care about one table, or omit filters entirely to watch all non-system schemas. The default poll interval is 5 seconds; use --interval 2s when you want faster regeneration.

Exact KalamDB datatype mapping

KalamDB typeGenerated Drizzle helperRead behavior
BOOLEANboolean()boolean
INTinteger()number
SMALLINTsmallint()number
BIGINTtext() by defaultstring for Int64 precision
DOUBLEdoublePrecision()number
FLOATreal()number
TEXTtext()string
TIMESTAMPtimestamp(..., { mode: 'date' })Date when using date mode
DATETIMEtimestamp(..., { mode: 'date' })Date when using date mode
DATEdate(..., { mode: 'date' })UTC-date Date
TIMEtime()HH:mm:ss[.fraction] string
JSONjsonb()JSON value
BYTESbytes()Uint8Array
EMBEDDING(n)embedding(name, n)number[]
UUIDuuid()UUID string
DECIMAL(p,s)numeric()exact decimal string
FILEfile()`FileRef

Live table helpers

Use liveTable() for React state, dashboards, and admin UI screens that want the current materialized row set.

ts snippetTS
import { liveTable } from '@kalamdb/orm';import { messages } from './schema'; const stop = await liveTable(client, messages, (rows) => {  setRows(rows);}, {  lastRows: 100,}); await stop();

liveTable() reuses the same @kalamdb/client connection and normalizes timestamp/date/time fields from the Drizzle table metadata. It accepts the same row-oriented options as client.live(), including lastRows, from, limit, getKey, and onCheckpoint. Use client.liveEvents() directly when you need low-level change events.

UI and example fit

Use this package in UI code or service code that wants typed tables. Worker code should import @kalamdb/consumer only when it needs topic consumption.

Copy This Project Shape

text snippetTEXT
src/  db/    schema.ts      # generated by kalamdb-orm    client.ts      # createClient() + kalamDriver(client)  app/    messages.ts    # Drizzle queries against generated tables
Last updated on