Skip to Content

SQL, Functions & Typed SDKs

KalamDB combines the database and application runtime. Define your contracts in SQL, implement server functions in TypeScript, and use generated clients or live queries in your app.

These examples follow the current schema-generated API. Keep the server, CLI, and SDK versions aligned when adopting new APIs.

Start a project

Start a 0.8 server with the server quick start, then install the matching TypeScript client in your app:

BASH
npm install @kalamdb/client@0.8.0

The published CLI’s chat-with-ai and simple-live TypeScript starters currently pin 0.7 beta SDK packages, so they are not ready to run against 0.8 unchanged. See the starter status before using them.

Declare a function contract in SQL

Add a function declaration to your project’s kalam/schema.sql:

SQL
CREATE SCHEMA IF NOT EXISTS app; CREATE FUNCTION app.greet(  first_name TEXT NOT NULL,  last_name TEXT NOT NULL)RETURNS TEXTSECURITY INVOKER; GRANT EXECUTE ON FUNCTION app.greet TO user;

CREATE FUNCTION ... RETURNS ... declares a function with a result. CREATE PROCEDURE declares a procedure invoked with CALL, including topic handlers. Built-in SQL expression functions are documented separately in the SQL reference.

Generate the project’s contracts:

BASH
kalam schema gen

Implement the function

Use the generated builder in functions/src/app/greet.ts:

TS
import { procedure } from '../generated/contracts'; export const greet = procedure.app.greet(async (ctx, input) => {  // ctx.orm and ctx.db share this call's transaction.  // Commit on success; rollback on error.  return `Hello, ${input.first_name} ${input.last_name}!`;});

The procedure export is the generated TypeScript implementation builder for routines, including SQL functions. It carries the argument and result types from your schema.

Keep kalam dev running to build and activate your implementation. For a configured deployment environment:

BASH
kalam deploy --env dev

The CLI compiles TypeScript to JavaScript. KalamDB executes the deployed module in its embedded V8 runtime. See the function build and deployment workflow.

Call through a generated client

With the authenticated client for your application:

TS
import { createKalam } from './generated/kalam';import { client } from './db'; const api = createKalam(client);const greeting = await api.app.greet({  first_name: 'Ada',  last_name: 'Lovelace',});// Missing last_name or passing a number fails TypeScript checking.

Generate Dart contracts with kalam schema gen --languages dart to call the same function:

DART
import 'generated/kalam.dart';import 'db.dart'; final api = KalamFunctions(client);final greeting = await api.app.greet(  AppGreetRequest(firstName: 'Ada', lastName: 'Lovelace'),);// Both named parameters are required strings.

Both generated clients bind argument values separately from SQL. NOT NULL makes these fields required in the generated requests; the server also validates arguments.

The generated API owns the request and response contract. You can also invoke backend routines through HTTP or SQL, subject to authentication and EXECUTE permissions.

Subscribe to the data

The chat starter exports an authenticated client from src/db.ts:

TS
import { client } from './db'; const stop = await client.live(  "SELECT id, content FROM chat_demo.messages WHERE room = 'main'",  (rows) => console.log(rows),  {    lastRows: 100,    limit: 100,    onError: console.error,  },); // Call await stop() when the view is disposed.

live() maintains the row set for you. Use React hooks and components to bind subscriptions to a component’s lifecycle, or the typed ORM to work with generated table definitions.

For Flutter apps, start with the Dart SDK and kalam_sync. Native services and workers can use the Rust SDK.

Connect a background worker

The chat starter routes message inserts to a durable topic:

SQL
CREATE TOPIC chat_demo.ai_inbox;ALTER TOPIC chat_demo.ai_inbox  ADD SOURCE chat_demo.messages ON INSERT;

Its topic trigger invokes the declared chat_demo.on_user_message procedure inside KalamDB. That procedure writes progress and the reply back to tables, and subscribed clients receive those changes.

External consumers can use consumer groups and acknowledgements to process durable work. See topics and consumers and the TypeScript consumer SDK.

Deploy the same backend

Start with a single server and local disk. Use Multi-Raft clustering when deploying multiple replicated nodes, and PGWire to connect existing SQL tools directly.

More examples