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 with IF 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 EXISTS so 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.