Browser SDK
The @db9/browser SDK lets you query DB9 databases directly from browser and edge environments. All queries flow through the public data API with Row-Level Security (RLS) enforcement — you never expose raw connection strings or admin credentials to the client.
When to Use the Browser SDK
Section titled “When to Use the Browser SDK”| Scenario | Recommended tool |
|---|---|
| Client-side data access with per-user RLS | Browser SDK — @db9/browser |
| Server-side provisioning, migrations, fs9 | Node.js SDK — get-db9 (TypeScript SDK) |
| Terminal database management | CLI — db9 (CLI Reference) |
| ORM or driver connection from a backend | Raw pgwire — use the connection string (Connect) |
Installation
Section titled “Installation”Works in any environment with fetch — browsers, Deno, Cloudflare Workers, Next.js client components.
npm install @db9/browserAlso available via pnpm add @db9/browser, yarn add @db9/browser, or bun add @db9/browser.
Prerequisites
Section titled “Prerequisites”Before using the browser SDK you need:
- A database — create one with
db9 createor the Node.js SDK. - A publishable key — create one via the REST API (see Security & Auth — Publishable Keys).
- (Optional) Auth config — if you want per-user RLS, configure BYO JWT on the database (see Security & Auth — BYO JWT).
Quick Start
Section titled “Quick Start”import { createDb9BrowserClient } from '@db9/browser';
const db9 = createDb9BrowserClient({ apiUrl: 'https://api.db9.ai', databaseId: 'your-database-id', anonKey: 'db9pk_your_publishable_key',});
// Read rowsconst { data, error } = await db9.from('todos').select('*');
if (error) { console.error(error.message, error.statusCode);} else { console.log(data); // [{ id: 1, task: '...', done: false }, ...]}createDb9BrowserClient(options)
Section titled “createDb9BrowserClient(options)”Creates a client instance. The client is stateless — no persistent connections are opened until a query executes.
function createDb9BrowserClient(options: Db9BrowserClientOptions): Db9BrowserClient;| Option | Type | Required | Description |
|---|---|---|---|
apiUrl | string | Yes | Base URL of the DB9 API (e.g., https://api.db9.ai). |
databaseId | string | Yes | Target database ID. |
anonKey | string | Yes | Publishable key (db9pk_...). Safe to embed in client-side code. |
fetch | typeof fetch | No | Custom fetch implementation (e.g., for testing or polyfills). |
timeout | number | No | Request timeout in milliseconds. |
Authentication (client.auth)
Section titled “Authentication (client.auth)”Without authentication, queries run under the anonymous role. To enable per-user RLS enforcement, attach a JWT from your auth provider.
Static Token
Section titled “Static Token”Set a token you already have (e.g., after login):
db9.auth.setSession({ accessToken: userJwt });Token Provider (Auto-Refresh)
Section titled “Token Provider (Auto-Refresh)”Supply an async function that is called before each request — ideal for expiring tokens:
db9.auth.setAccessTokenProvider(async () => { return await myAuthService.getAccessToken();});Inspect or Clear Session
Section titled “Inspect or Clear Session”const session = db9.auth.getSession();// { accessToken: '...' } or null
db9.auth.clearSession(); // reverts to anonymous roleAuth Reference
Section titled “Auth Reference”| Method | Description |
|---|---|
setSession({ accessToken }) | Set a static JWT token. |
setAccessTokenProvider(fn) | Set an async token provider called before each request. |
getSession() | Returns { accessToken } or null. |
clearSession() | Removes token and provider; reverts to anonymous role. |
Query Builder
Section titled “Query Builder”All queries start with db9.from(table), which returns a TableRef. From there, chain into one of four operations: select, insert, update, or delete.
Every query returns Db9Result<Row[]> — an object with { data, error }. The SDK never throws on API errors; check error instead.
type Row = Record<string, unknown>;
interface Db9Result<T> { data: T | null; error: Db9BrowserError | null;}SELECT
Section titled “SELECT”// All columns, all rows (up to server default limit of 100)const { data } = await db9.from('todos').select('*');
// Specific columnsconst { data } = await db9.from('todos').select('id', 'task');
// With filters, ordering, and paginationconst { data } = await db9 .from('todos') .select('*') .eq('status', 'active') .order('created_at', 'desc') .limit(20) .offset(40);SelectBuilder Methods
Section titled “SelectBuilder Methods”| Method | Signature | Description |
|---|---|---|
select | (...columns: string[]) | Columns to return. '*' or omit for all. |
eq | (column, value) | column = value |
neq | (column, value) | column != value |
gt | (column, value) | column > value |
gte | (column, value) | column >= value |
lt | (column, value) | column < value |
lte | (column, value) | column <= value |
like | (column, pattern) | column LIKE pattern |
ilike | (column, pattern) | column ILIKE pattern (case-insensitive) |
in | (column, values[]) | column IN (...) |
is | (column, null | boolean) | column IS NULL / column IS NOT NULL |
filter | (column, op, value) | Generic filter with any FilterOperator. |
order | (column, 'asc' | 'desc') | Sort results. Default: 'asc'. Chainable for multi-column sort. |
limit | (count) | Max rows to return (server max: 1000). |
offset | (count) | Skip rows for pagination. |
INSERT
Section titled “INSERT”const { data, error } = await db9 .from('todos') .insert({ task: 'Ship browser SDK', status: 'active' }) .returning('*');| Method | Signature | Description |
|---|---|---|
values | (record) | Set column values. Also accepted as argument to insert(). |
returning | (...columns) | Columns to return from the inserted row. '*' for all. |
UPDATE
Section titled “UPDATE”const { data, error } = await db9 .from('todos') .update({ status: 'done' }) .eq('id', 42);| Method | Signature | Description |
|---|---|---|
set | (record) | Set column values. Also accepted as argument to update(). |
eq | (column, value) | Filter rows to update. |
filter | (column, op, value) | Generic filter. |
DELETE
Section titled “DELETE”const { data, error } = await db9 .from('todos') .delete() .eq('id', 42);| Method | Signature | Description |
|---|---|---|
eq | (column, value) | Filter rows to delete. |
filter | (column, op, value) | Generic filter. |
Schema-Qualified Tables
Section titled “Schema-Qualified Tables”To query tables outside the public schema, use dot notation:
const { data } = await db9.from('analytics.events').select('*');The schema must be listed in the publishable key’s exposed_schemas.
Error Handling
Section titled “Error Handling”The SDK returns errors in Db9Result.error instead of throwing. The error object includes a human-readable message and the HTTP status code.
const { data, error } = await db9.from('todos').select('*');
if (error) { console.error(`[${error.statusCode}] ${error.message}`); // e.g., [403] "table 'secrets' is not exposed by this key" // e.g., [401] "invalid or expired publishable key"}Db9BrowserError
Section titled “Db9BrowserError”class Db9BrowserError extends Error { readonly statusCode: number;}| Status Code | Meaning |
|---|---|
400 | Invalid request (bad filter, missing values). |
401 | Invalid publishable key or expired JWT. |
403 | Table or schema not exposed by the key, or RLS denied access. |
404 | Database not found. |
429 | Rate limit exceeded (configure via publishable key). |
TypeScript Types Reference
Section titled “TypeScript Types Reference”All types are exported from the package entry point:
import type { Db9BrowserClientOptions, Db9BrowserClient, Db9Auth, AccessTokenProvider, QueryOperation, FilterOperator, QueryFilter, QueryOrder, QueryRequest, QueryResponse, ColumnInfo, QueryError, Db9Result, Row,} from '@db9/browser';
import { createDb9BrowserClient, Db9BrowserError, SelectBuilder, InsertBuilder, UpdateBuilder, DeleteBuilder, TableRef,} from '@db9/browser';Full Example: Next.js with Auth
Section titled “Full Example: Next.js with Auth”// lib/db9.tsimport { createDb9BrowserClient } from '@db9/browser';
export const db9 = createDb9BrowserClient({ apiUrl: process.env.NEXT_PUBLIC_DB9_API_URL!, databaseId: process.env.NEXT_PUBLIC_DB9_DATABASE_ID!, anonKey: process.env.NEXT_PUBLIC_DB9_ANON_KEY!,});// components/TodoList.tsx'use client';
import { useEffect, useState } from 'react';import { db9 } from '../lib/db9';import { useAuth } from '../hooks/useAuth';
export function TodoList() { const { jwt } = useAuth(); const [todos, setTodos] = useState([]);
useEffect(() => { if (jwt) { db9.auth.setSession({ accessToken: jwt }); } else { db9.auth.clearSession(); } }, [jwt]);
useEffect(() => { async function load() { const { data, error } = await db9 .from('todos') .select('*') .order('created_at', 'desc') .limit(50);
if (data) setTodos(data); } load(); }, [jwt]);
return ( <ul> {todos.map((t) => ( <li key={t.id}>{t.task}</li> ))} </ul> );}Related Docs
Section titled “Related Docs”- TypeScript SDK — server-side Node.js SDK for provisioning and admin
- Security & Auth — publishable keys, BYO JWT configuration
- Row-Level Security — RLS policies and enforcement
- CLI Reference — terminal-based database management