JavaScript SDK - Data#
The data builder mirrors PostgREST-style DX and is fully typed.
Typed rows#
type Message = {
message_id: string;
user_id?: string | null;
message: string;
full_name?: string | null;
created_at: string; // ISO string
};
const rows = await db.from<Message>('messages').select('id as message_id, message').limit(10);
rows.data![0].message_id; // typed string
TypeScriptfrom<Row>() types execute, get, single, insert, update and awaited
chains (including joins).
Read#
// Select all
await db.from('profiles').select();
// Select columns
await db.from('profiles').select('id, nationality');
// Single row by primary key
await db.from('profiles').get(recordId);
// First matching row
await db.from('profiles').eq('nationality', 'Kenya').single();
// Row count only (no rows transferred)
const { data: { count } } = await db.from('profiles').head();
TypeScriptFilters#
| Method | SQL |
|---|---|
.eq(col, v) | col = v |
.neq(col, v) | col != v |
.gt(col, v) / .gte(col, v) | col > v / col >= v |
.lt(col, v) / .lte(col, v) | col < v / col <= v |
.like(col, '%x%') | LIKE |
.ilike(col, '%x%') | ILIKE (case-insensitive) |
.isNull(col) / .isNotNull(col) | IS NULL / IS NOT NULL |
.in(col, ['a','b']) | IN (...) |
Filters chain with AND.
Ordering and pagination#
await db.from('profiles').order('created_at', { ascending: false });
await db.from('profiles').limit(50).offset(100);
TypeScriptFor large tables use keyset pagination (O(1) per page vs O(n) for offset):
let page = await db.from('logs').select('id').limit(100);
while (page.data!.length) {
const lastId = String(page.data![page.data!.length - 1].id);
// process page...
page = await db.from('logs').select('id').limit(100).cursor(lastId);
}
TypeScriptJoins#
Column-picker joins - no SQL needed:
const rows = await db
.from('messages')
.select('id as message_id, message, users.full_name as full_name')
.join({ type: 'LEFT JOIN', table: 'users', from_column: 'user_id', to_column: 'id' })
.limit(20);
// rows include users.full_name (aliased as full_name)
TypeScript.join({ type, table, from_column, to_column })builds the ON clause.join({ type, table, on: 'base.id = join.user_id' })raw clause (advanced)- Chain multiple joins; the
userstable joins are auto-scoped to the project - Joined columns are keyed as
{table}.{column}(or your alias)
Write#
// Insert single or many (server fills id/created_at)
const one = await db.from<Message>('messages').insert({ message: 'hi' });
const many = await db.from<Message>('messages').insert([{ message: 'a' }, { message: 'b' }]);
// Update (requires .eq('id', ...))
await db.from('profiles').update({ nationality: 'Kenya' }).eq('id', recordId);
// Delete (requires .eq('id', ...))
await db.from('profiles').delete().eq('id', recordId);
TypeScriptRaw request#
For endpoints without a dedicated method:
await db.request('/projects/.../custom', { method: 'POST', body: JSON.stringify({...}) });
TypeScriptNext: Auth.