Skip to content

Drizzle

Rizky Zulkarnaen edited this page Sep 9, 2026 · 1 revision

Drizzle

Source of truth: docs/drizzle.md · ADR: ADR-0026

Lugas integrates Drizzle ORM through the optional lugas/drizzle subpath: your application-owned instance, declared as a Lugas service. The adapter never imports drizzle-orm — Drizzle stays at the version your app chooses, and Lugas keeps zero production dependencies.

import { Database } from "bun:sqlite";
import { drizzle } from "drizzle-orm/bun-sqlite";
import { defineApp, json, route } from "lugas";
import { drizzleService } from "lugas/drizzle";

const db = drizzle(new Database("app.sqlite"));

export default defineApp({
  services: {
    database: drizzleService({ db, name: "database" }),
  },
  routes: {
    "/users": {
      GET: route<{ database: typeof db }>({
        handler: async (ctx) => {
          const rows = await ctx.services.database.all(`SELECT id, name FROM users ORDER BY id`);
          return json(200, rows);
        },
      }),
    },
  },
});

Guarantees

  • Startup validation — missing structural CRUD surface (select/insert/update/delete functions) fails at declaration with LUGAS_DRIZZLE_001, not at first request.
  • Exact instance type survives into ctx.services.<name>select(), query, and $client typecheck.
  • No implicit I/O — no connection, query, ping, or migration at startup; no migrate() API exists.
  • No transaction wrapping — Drizzle owns transactions and savepoints.
  • Driver-agnostic — no driver branches in the adapter; any Drizzle driver works.
  • Replaceable in tests — validation is structural (no instanceof), so fakes are valid services.

Shutdown

Default: no dispose — the application owns closing its database. Explicit opt-in:

drizzleService({ db, name: "database", closeOnDispose: true });

This wires dispose through the structural $client.close() during drain-ordered shutdown. No closable client (e.g. a pool exposing end() instead)? Declaration fails closed with LUGAS_DRIZZLE_002 — compose service() directly and dispose however your client requires.

Scope (what Lugas does not do)

Schema design, migrations, transactions, pooling, tenancy, and credentials stay application-owned. See Home for the full battery list and Compatibility and Roadmap for the post-beta.2 sequence.

Clone this wiki locally