Koze Integration | Kunii | Primitives Docs

Koze Integration

Wire kunii into your Koze app via middleware

The framework no longer reads a project-level config file. The ORM plugs in through ordinary middleware steps and explicit constructor calls inside Durable Objects — so kunii is a library you opt into, not a framework feature.

D1 (cold-start initialization)

Wire the Koze adapter into src/middleware.ts. The first request per worker isolate runs migrations against the D1 binding; subsequent requests short-circuit via an in-isolate flag.

// src/middleware.ts
import { defineMiddleware } from '@kuratchi/koze';
import { initKuniiORM } from '@kuratchi/kunii/koze';
import { appSchema } from './server/schemas/app';

const orm = initKuniiORM({ DB: appSchema });

export default defineMiddleware({
  orm: orm.middleware(),
});

The map key (DB) must match the Wrangler binding name. You can register multiple D1 databases in one init:

const orm = initKuniiORM({ DB: appSchema, ANALYTICS: analyticsSchema });

The older autoMigrate({ DB: appSchema }) helper remains supported:

import { autoMigrate } from '@kuratchi/kunii';

export default defineMiddleware({
  migrate: autoMigrate({ DB: appSchema }),
});

D1 (query client)

Inside any server module, $server/* route helper, action, or RPC handler:

// src/server/items.ts
import { kunii } from '@kuratchi/kunii';
import { env } from 'cloudflare:workers';
import { appSchema } from './schemas/app';

const db = kunii(() => env.DB, appSchema);

export async function listItems() {
  return db.items.orderBy({ created_at: 'desc' }).many();
}

Lazy binding (() => env.DB) lets the module live at top-level without resolving env at import time.

Durable Objects

Run initKuniiDO(ctx.storage, schema) synchronously in the constructor:

// src/server/notes.do.ts
import { DurableObject } from 'cloudflare:workers';
import { initKuniiDO } from '@kuratchi/kunii';
import { notesSchema } from './schemas/notes';

export default class NotesDO extends DurableObject {
  db;

  constructor(ctx, env) {
    super(ctx, env);
    this.db = initKuniiDO(ctx.storage, notesSchema);
  }

  async list() {
    return this.db.notes.orderBy({ created_at: 'desc' }).many();
  }
}

initKuniiDO runs CREATE TABLE IF NOT EXISTS plus additive ALTER TABLE ADD COLUMN for any new columns, then returns the query client. Idempotent across DO restarts.

Pass ctx.storage (preferred) so atomic db.batch() can use transactionSync. Pass ctx.storage.sql if you only need the SQL surface.

Opt-out: external migrations

If you'd rather manage D1 migrations out-of-band (CI running wrangler d1 migrations apply against hand-written SQL), simply omit the ORM middleware step. kunii(env.DB, schema) is a query client — it never issues DDL.

For BYO migration workflows, the underlying DDL helpers are exported under kunii/migrations:

import { buildInitialSql, buildDiffSql, diffSchemas } from '@kuratchi/kunii/migrations';

// First-time creation
const sql = buildInitialSql(appSchema);

// Diff against an existing DB shape
const { sql: upgradeSql, warnings } = buildDiffSql(currentSchema, appSchema);

See Migrations for the full reference.

Dev-mode schema drift check

Drop assertSchemaInSync into your middleware behind an import.meta.env.DEV guard to throw if the live database has drifted from the declared schema — catches missing migration wiring before it surfaces as confusing no such table errors at runtime:

import { assertSchemaInSync } from '@kuratchi/kunii';
import { initKuniiORM } from '@kuratchi/kunii/koze';

const orm = initKuniiORM({ DB: appSchema });

export default defineMiddleware({
  schemaCheck: import.meta.env.DEV
    ? assertSchemaInSync({ DB: appSchema })
    : null,
  orm: orm.middleware(),
  // ...
});

Migrating from kuratchi.config.ts

Earlier versions had an orm: kuratchiOrmConfig({ databases: {...} }) block in kuratchi.config.ts. Each entry maps cleanly:

Old New
DB: { schema: appSchema } orm: initKuniiORM({ DB: appSchema }).middleware() in src/middleware.ts
DB: { schema: appSchema, skipMigrations: true } Omit the binding from initKuniiORM({...})
NOTES_DO: { schema: notesSchema, type: 'do' } initKuniiDO(ctx.storage, notesSchema) in the DO constructor

The kuratchiOrmConfig adapter and the kuratchi.config.ts file are gone — delete both.