Type generation
Generate TypeScript types, Zod schemas, or a Drizzle schema from the live database schema - and gate CI on schema drift.
Quickstart
In a linked project directory (capydb link):
capydb generate types # writes database.types.tsGeneration runs server-side against the live schema of your cell - one implementation shared by the CLI, the API, and the MCP server - so the output is identical no matter which surface asked for it. The CLI just fetches the result and writes the file.
Every generator takes the same flags:
--out <path>/-o- output file (defaults to the generator's suggested filename)--print- print to stdout instead of writing a file--preview <id>- generate from a preview database instead of the project database--project <ref>- project id, slug, or name (defaults to the linked project)
TypeScript
The default style (capydb) emits per-table Row / Insert / Update interfaces plus a Database aggregate that mirrors them:
export interface UsersRow { ... }
export interface UsersInsert { ... } // generated/defaulted columns optional
export interface UsersUpdate { ... } // everything optional
export type Database = {
public: {
Tables: {
users: { Row: UsersRow; Insert: UsersInsert; Update: UsersUpdate };
};
...
};
};Porting from Supabase
--style supabase emits a supabase-js-compatible Database generic instead, including the Tables<T> / TablesInsert<T> / TablesUpdate<T> / Enums<T> helper types:
capydb generate types --style supabaseIf you imported a Supabase project and your code is full of Tables<"users"> references, this style is a drop-in replacement for supabase gen types typescript - regenerate against your CapyDB cell and the existing type references keep compiling.
Zod
capydb generate zod # writes database.zod.tsEmits a z.object(...) row schema per table plus inferred Row types - useful when you validate data at runtime (API boundaries, form input) rather than only at compile time.
Two ways to Zod
There are two complementary sources of truth for runtime validators:
- Database-first -
capydb generate zodderives validators from the live schema. Right when the database is the source of truth (imported/legacy schemas, SQL-managed migrations, or no ORM at all): the validators track what the database actually enforces. - Schema-first - drizzle v1 ships validator generation in core:
createSelectSchema/createInsertSchemafromdrizzle-orm/zodderive validators from your Drizzle table objects. Right when your Drizzle schema file is the source of truth and migrations flow through drizzle-kit - validators update the moment the schema file does, no regeneration step.
// schema-first: validators straight from your Drizzle tables
import { createInsertSchema, createSelectSchema } from 'drizzle-orm/zod'
import { users } from './db/schema'
const userRow = createSelectSchema(users)
const newUser = createInsertSchema(users)They compose: bootstrap with capydb generate drizzle, then let drizzle-orm/zod derive validators from that schema file going forward.
Drizzle
capydb generate drizzle # writes schema.tsRenders the live schema as a Drizzle ORM schema file - tables, enums, and foreign keys as pgTable / pgEnum declarations. This is the "database-first" entry into Drizzle: point it at an existing cell and start querying with full types. capydb init drizzle goes one step further and scaffolds the config and client around it - see the Drizzle guide.
Generating against a preview branch in CI
The GitHub Action creates a preview database per pull request; --preview generates types from that branch database instead of production, so a PR that migrates the schema also carries the matching types:
- name: Create preview database
id: capydb
uses: capy-base/capydb-preview-action@v1
with:
api-key: ${{ secrets.CAPYDB_API_KEY }}
project-id: ${{ vars.CAPYDB_PROJECT_ID }}
- name: Run migrations against the preview
run: pnpm db:migrate # DATABASE_URL / DATABASE_URL_UNPOOLED already exported
- name: Verify committed types match the migrated schema
env:
CAPYDB_API_KEY: ${{ secrets.CAPYDB_API_KEY }}
run: |
capydb generate types --preview "${{ steps.capydb.outputs.preview-id }}" --out database.types.ts
git diff --exit-code database.types.tsIf the generated file differs from what the PR committed, the diff fails the job - the types can never silently lag the schema.
Drizzle-kit v1 users should add one more gate before migrating: drizzle-kit check detects migrations that conflict across git branches (two PRs each adding a migration that doesn't commute), and drizzle-kit push --explain previews the exact DDL a push would run without executing it:
- name: Migration hygiene (drizzle-kit v1)
run: pnpm drizzle-kit checkDrift gating with schema dump and diff
capydb schema dump writes the canonical schema document as deterministic JSON - the same structural facts the generators consume (tables, columns, constraints, enums, extensions). Because the output is deterministic, it can be committed and diffed like source:
capydb schema dump --out schema.jsoncapydb schema diff compares the live schema against a committed snapshot or another preview database, and --exit-code makes it behave like git diff --exit-code - differences flip the exit status so CI can gate on drift:
# Has production drifted from the committed snapshot?
capydb schema diff --against schema.json --exit-code
# What does this PR's preview change relative to production?
capydb schema diff --against-preview <preview-id>--against accepts either a bare capydb schema dump file or a raw API response envelope. Combine --preview with --against to check a branch database against the snapshot instead.
Scoped API keys for CI
The schema endpoints accept any API key with projects:read - or a key carrying only the narrow schema:read scope. A schema:read-only key can introspect and generate types but cannot read credentials, run SQL, or touch lifecycle operations, which makes it the right shape for typegen-only CI jobs. Create one in the dashboard under Settings → API keys, project-scoped to the repository's project.
API
Everything above is a thin wrapper over four endpoints (see the Schema tag in the API reference):
GET /v1/projects/{id}/schema
GET /v1/projects/{id}/schema/types?language=typescript|zod|drizzle&style=capydb|supabase
GET /v1/preview-databases/{id}/schema
GET /v1/preview-databases/{id}/schema/types?language=...&style=.../schema returns the canonical schema document; /schema/types returns { language, style, filename, content }. style only applies to language=typescript.
For agents
The MCP server exposes the same capabilities as get_schema and generate_types. get_schema returns the whole schema in one call - agents should prefer it over introspecting pg_catalog with run_sql - and generate_types returns { filename, content } for the agent to write into the repo, with preview_id for branch databases. For the wider pattern of letting agents change schemas safely, see the agent safety loop.