05·Hands-on·14 min

Data over the API

Two doors into your database: one for the shape, one for the rows.

Migrations change the shape

await client.db.migrate({
    sql: 'CREATE TABLE IF NOT EXISTS profiles (id serial primary key, name text not null)',
})

This is the only place DDL enters a project database from outside. Statements run through the same pipeline the console uses: single-schema isolation, no role or permission management, no extensions, and the platform-managed users table is protected. The response lists the executed statements and any warnings; a failed statement returns 400 and nothing is half-applied.

Queries move the rows

Queries are structured objects, never SQL strings:

const rows = await client.db.profiles.find({ where: { name: { startsWith: 'K' } }, limit: 20 })
const { id } = await client.db.profiles.insert({ name: 'Kim' })
await client.db.profiles.update({ where: { id }, data: { name: 'Kim Minji' } })

find returns up to 1000 rows per call; use limit and offset to page. update and delete require a where. Every value is parameterized on the server, so a name containing a quote is just a name.

Conflicts are the idempotency tool

A unique or foreign-key violation returns 409. That is the supported pattern for "create if missing": insert, and on 409 treat the row as existing or read it back. No pre-check race.

Budgets

Reads (find, findOne, count) and writes (insert, update, delete) spend from separate per-minute budgets, and migrate has its own small one. A polling loop that exhausts reads still gets its writes through.

Where DontCode fits

The Database page in the console shows the same schema and rows your code creates, so you can watch a migration land in the Schema view. Row-level security policies are yours to write in a migration; the gateway runs queries inside your project's schema, so a policy applies to API traffic like any other.

Go deeper

Check your understanding

  1. 1.Where can raw SQL be sent to the gateway?

  2. 2.An insert returns 409. What does it mean?

  3. 3.What happens to an update with no where clause?

Your task

Backend Project

From your code, run a migration with client.db.migrate (or POST /api/v1/db/migrate) that creates a table or adds a column. The check passes when the migration applies successfully; confirm it in the console's Database page.