# Koze Integration

> Wire kunii into your Koze app via middleware

Package: Kunii
Canonical: https://kuratchi.dev/docs/kunii/koze-integration
Markdown: https://kuratchi.dev/docs/kunii/koze-integration.md

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.

```ts
// 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:

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

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

```ts
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:

```ts
// 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:

```ts
// 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`:

```ts
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](/docs/kunii/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:

```ts
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.
