Core Concepts — Migrations & Seeding
This section explains how tables are created and boot data is loaded when using vibecode‑db with different adapters. Keep it simple: SQLite adapters run your migrations, and seeding is optional demo/test data.
What runs where
- SQLite (Web / Expo): you provide a
migrations: string[]of SQL DDL. The adapter runs them on startup (typically idempotent withIF NOT EXISTS). - Supabase: migrations are managed in your Supabase/Postgres project (outside vibecode‑db). You still get the same query API and types from your schema.
We intentionally avoid documenting internal cores here; focus on adapter behavior you control.
Minimal migrations array (example)
1// db/migrations.ts
2export const migrations: string[] = [
3 // users
4 `CREATE TABLE IF NOT EXISTS users (
5 id INTEGER PRIMARY KEY,
6 name VARCHAR,
7 email VARCHAR
8 );`,
9
10 // todos (FK → users.id)
11 `CREATE TABLE IF NOT EXISTS todos (
12 id UUID PRIMARY KEY,
13 title VARCHAR,
14 completed BOOLEAN,
15 created_at TIMESTAMP,
16 updated_at TIMESTAMP,
17 user_id INTEGER,
18 FOREIGN KEY(user_id) REFERENCES users(id)
19 );`,
20
21 // optional index
22 `CREATE INDEX IF NOT EXISTS todos_created_at_idx ON todos (created_at);`
23]- Use
IF NOT EXISTSso reruns are safe. - Enforce integrity/uniqueness you need here (e.g., unique email), since the current DSL doesn’t declare constraints explicitly.
Wiring migrations per environment (pattern only)
1// Web (sqlite-web)
2new SQLiteAdapter(ctx, { wasm: { wasmUrl: '/sql-wasm.wasm' }, migrations })
3
4// Expo (sqlite-expo)
5new SQLiteAdapter(ctx, { native: { dbName: 'vibecode.db' }, migrations })The client DSL gives you schema and relations; migrations create the physical tables/keys in SQLite.
Seeding (optional boot data)
Provide initial rows per table via dbSpec.seed. Keep it small and deterministic—great for demos/tests.
1export const dbSpec = {
2 schema: db.zodBundle,
3 relations: db.relations,
4 seed: {
5 users: [
6 { id: 1, name: 'Ada', email: 'ada@example.com' },
7 { id: 2, name: 'Alan', email: 'alan@example.com' },
8 ],
9 todos: [
10 { id: 't1', title: 'Wire the UI', completed: false, user_id: 1, created_at: new Date(), updated_at: new Date() },
11 ],
12 },
13}- Seed consumption is adapter‑specific; SQLite adapters typically insert if empty. If you need strict idempotency, prefer UPSERT in a custom bootstrap.
Practical tips
- Keep table/column names in migrations exactly aligned with your schema DSL.
- Add indexes for read paths you care about (created_at, foreign keys).
- When changing models, ship a new migration instead of editing prior ones.
- For Supabase, manage DDL in your Postgres toolchain; vibecode‑db remains your front‑end query/types layer.
Summary
- SQLite adapters run your SQL migrations and can apply seed data.
- Supabase manages schema outside vibecode‑db, but your API and types stay the same.
Define models in the DSL, run migrations where needed, and keep seed data tiny and repeatable.