Keel

Docs / Database / Schema overview

Schema overview

Keel uses Drizzle ORM over Postgres, connected via postgres-js (a standard DATABASE_URL, not a provider-specific HTTP driver), so it works unchanged against Neon, Supabase, Railway, or a local Postgres instance.

File organization

Schema files live under lib/db/schema/*:

  • auth-schema.ts, Better Auth's own tables (user, session, account, verification). Generated by npx @better-auth/cli generate, never hand-edited, see Sessions & middleware.
  • Everything else (team.ts, billing.ts, credits.ts, api-keys.ts, notifications.ts, feature-flags.ts, app-settings.ts, audit-log.ts, relations.ts), Keel's own domain tables, re-exported through app.ts.
  • index.ts re-exports both app.ts and auth-schema.ts, the single import surface the rest of the app uses (import { teams, credits } from "@/lib/db/schema").
  • columns.ts holds three shared column builders used across every custom table: id() (a UUID primary key formatted to match Better Auth's own id shape, so joins between the two stay consistent), createdAt(), and updatedAt() (auto-touches on every update via $onUpdate).

The tables

Teams, billing, and AI credits: teams, team_members, invites, subscriptions, credit_purchases, checkout_locks, credits, usage_events. Everything else: api_keys, notifications, feature_flags, app_settings, audit_log.

Every custom table carries a team_id

Teams/RBAC are core v1, not a bolt-on, so every table above (including credits and usage_events, not just the obviously "team" ones) has a team_id foreign key from its first migration. See Team model for the full rule and why it's enforced through lib/dal/*.ts rather than left to callers.

Adding a table

Add the Drizzle table definition to a new or existing file under lib/db/schema/, re-export it from app.ts if it's a new file, then generate and apply a migration, see Migrations. Read the table through a lib/dal/*.ts function, not an inline query in a route handler, matching every existing table.

Edit this page on GitHub →Last updated Jul 22, 2026