From the browser
The browser SDK — imported as tada from src/lib/tada.ts — is the fastest path. tada.records.list() takes a table's api_slug (from tada/schema.json) and returns the RLS-scoped records for the signed-in user. Wrap it in useJson for loading / error / revalidation state.
import { useJson } from '@/lib/useJson';
import { tada } from '@/lib/tada';
export default function Customers() {
const { data, error, isLoading } = useJson(() =>
tada.records.list('customers', { limit: 25, order: 'created_at', orderBy: 'desc' }),
);
if (isLoading) return <p>Loading…</p>;
if (error) return <p>Failed to load.</p>;
return (
<ul>
{data?.items?.map((c) => <li key={c.id}>{c.field_1}</li>)}
</ul>
);
} Filter, search, and summarize
list() takes far more than page and limit. Filter with a condition group, keyword-search across searchable fields, and pull aggregates in the same call — all applied server-side, all still RLS-scoped.
// Overdue invoices, newest first, with a total
const { data } = await tada.records.list('invoices', {
filters: { items: [{ field_id: 'field_22', operator: 'is before today' }] },
order: 'field_22', orderBy: 'desc',
summary: ['count', 'sum:field_114'],
});
// data.items = [...] data.summary = { count: 7, 'sum:field_114': 12500 } From a backend route
When you need custom server logic — combining tables, calling a secret-guarded API, shaping a response — use the server SDK (TadaServer) inside a route under routes/. Pass the end-user's token so RLS still applies as that user.
import { TadaServer } from '../lib/tada-server.js';
const tada = TadaServer.fromEnv();
export async function listCustomers(req, res) {
const token = req.headers.authorization?.replace('Bearer ', '');
const { status, body } = await tada.listRecords(token, 'customers', { limit: 25 });
res.status(status).json(body);
} RLS just works
Every data call runs as the signed-in user through the Domain API. Tadabase's RLS is enforced server-side, record-by-record and field-by-field — if a user can't see a row in the builder, they can't see it through Vibe either.