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.Where can raw SQL be sent to the gateway?
2.An insert returns 409. What does it mean?
3.What happens to an update with no where clause?
Your task
Backend ProjectFrom 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.