Core Concepts — Schema

The schema is your single source of truth. You define tables, columns, and relations once with the vibecode‑db schema DSL; the system generates a Zod bundle for runtime validation and TypeScript types for compile‑time safety. Every adapter reads from this same definition.


What the schema gives you

  • Zod bundle: runtime validators derived from your DSL (db.zodBundle).
  • Type inference: static types across queries, inserts, and updates.
  • Relations graph: inferred from explicit FK declarations (used for nested reads).
  • Consistency: one definition powers all environments (Web/Expo/Supabase).

Mental model

  1. Define tables & columns with the DSL (defineSchema, vibecodeTable, column helpers like int, text, boolean, datetime).
  2. Declare foreign keys with references + col (e.g., user_id: references(col.integer('user_id'), () => db.tables.users.id)).
  3. You obtain db.zodBundle and db.relations.
  4. Build a DBSpec using these outputs and pass it to the client/adapter.

Example shape

1// db/schema.ts (illustrative)
2import { defineSchema, vibecodeTable, int, text, boolean, datetime, references, col } from '@vibecode-db/client'
3
4export const db = defineSchema({
5  users: vibecodeTable({
6    id: int().primaryKey(),
7    name: text().min(1),
8    email: text().email(),
9  }),
10  todos: vibecodeTable({
11    id: text().primaryKey(),
12    title: text(),
13    completed: boolean().default(false),
14    created_at: datetime(),
15    updated_at: datetime(),
16    user_id: references(col.integer('user_id'), () => db.tables.users.id),
17  }),
18})
19// Outputs -> db.zodBundle (validators), db.relations (FK graph)

Keep the schema minimal and expressive: model constraints where they matter (e.g., min(1), email(), primaryKey()), and declare relations explicitly.


Derived types

  • Input / Output models: inferred from your columns (e.g., insert vs select shapes).
  • Select pickers: nested projection strings (e.g., 'id, title, users(name)') map to typed results.
  • Partials: updates can infer partial shapes while preserving constraints where applicable.

Hand‑off to DBSpec

Use the schema outputs to assemble your DBSpec:

1{ schema: db.zodBundle, relations: db.relations, seed?, meta? }

Pass that to createClient({ dbSpec, adapter }). Adapters use your schema/relations for migrations (SQLite), validation, and nested reads.


Summary

Define it once with the DSL → get validators, types, and relations for free → plug into any adapter. This keeps your model portable and your queries type‑safe across environments.