Database — Insert Data

Create new rows with the same fluent surface across adapters. Inserts are schema-validated from your Zod bundle and work identically on SQLite (Web/Expo) and Supabase.

Prerequisite: You have a client created with a dbSpec (schema + relations [+ optional seed, meta]) and an adapter factory for SQLite Web/Expo or Supabase.


Execution Rule

  • Writes execute immediately. Calling .insert(...) performs the write.
  • Need the created row? Follow up with a select(...) (no inline returning here).

Basics

1// Insert a single user
2await db
3  .from('users')
4  .insert({
5    id: 3,
6    name: 'Grace',
7    email: 'grace@example.com',
8  })
1// Insert multiple rows
2await db
3  .from('posts')
4  .insert([
5    { id: 'p1', title: 'Hello',  user_id: 3 },
6    { id: 'p2', title: 'Second', user_id: 3 },
7  ])

Read-back pattern

If you need to show what you just created, read it back with a focused projection.

1await db.from('comments').insert({ id: 'c1', content: 'Nice!', post_id: 'p1', user_id: 3 })
2
3const created = await db
4  .from('comments')
5  .where({ id: 'c1' })
6  .limit(1)
7  .select('id, content, user_id')

Relations (quick note)

  • For FK columns (e.g., user_id), provide a value with the same kind as the target PK (integer → integer, uuid → uuid).
  • SQLite adapters today support one-level many-to-one nesting for reads; inserts are straightforward key writes.

Types & validation

  • Insert payloads are validated at runtime against your dbSpec.schema.
  • Types are inferred from the schema; your IDE will surface known fields.
  • Column names are checked against your schema to prevent typos.

Adapter notes (high level)

  • SQLite (Web / Expo): runs locally; your migrations (SQL DDL) create the physical tables/keys. Persistence: Web doesn't support, Expo on-device by default.
  • Supabase (bundled in @vibecode-db/client): remote Postgres; manage DDL in your Postgres migrations/tooling.

Summary

.insert(...) writes immediately and uses your schema for validation and typing. When you need the created row, issue a targeted select(...). The API is identical across adapters—only storage changes.