Database
View as markdown.mdAPI reference
Every database method, query modifier and filter operator in the Zeitlos SDK.
The database surface of @zeitlosapp/sdk.
Important
These calls are server-side only — server components, route handlers, server actions. See the quickstart.
Create Client
To operate with the database you'll need to create a client first.
import { createClient } from '@zeitlosapp/sdk';
const client = createClient(); // zero-config in a hosted app
const client = createClient<Database>(); // Define types for the shape of your databaseMethods
await client.from('posts').list();
await client.from('posts').get(id);
await client.from('posts').create({ title: 'Hello' });
await client.from('posts').update(id, { published: true });
await client.from('posts').delete(id);| Method | Returns | Notes |
|---|---|---|
list() | { records, nextCursor?, count? } | Applies any chained modifiers |
get(id) | the record | Throws record_not_found if missing |
create(input) | the created record | Don't pass id, created_at, updated_at |
update(id, input) | the updated record | Only the fields you pass |
delete(id) | void |
Query modifiers
Chain these before list():
| Modifier | Description |
|---|---|
.filter(filter) | Restrict results — see below |
.sort(...fields) | 'field' ascending, '-field' descending; multiple allowed |
.select(...fields) | Return only these fields |
.expand(...fields) | Inline related records one level deep, for relation fields |
.limit(n) | Page size — the gateway caps it |
.cursor(c) | Fetch the page after a previous result's nextCursor |
.withCount() | Also return the total match count |
const { records, nextCursor, count } = await client
.from('posts')
.filter({ published: true })
.sort('-created_at')
.limit(20)
.withCount()
.list();
const nextPage = await client.from('posts').cursor(nextCursor).list();Filters
A filter is an object. A bare value means equals; an object means { operator: value }.
Top-level fields are ANDed together.
.filter({ status: 'open' }) // equals
.filter({ views: { gte: 100 } }) // one operator
.filter({ title: { contains: 'sale' } }) // string operator
.filter({ tag: { in: ['a', 'b'] } }) // membership
.filter({ archivedAt: { isNull: true } }) // null checkCompose with and, or and not:
.filter({ or: [{ pinned: true }, { featured: true }] })
.filter({ and: [{ views: { gte: 100 } }, { status: 'open' }] })
.filter({ not: { status: 'draft' } })Operators
| Operator | Meaning |
|---|---|
eq / neq | Equals / does not equal |
gt / gte | Greater than / or equal |
lt / lte | Less than / or equal |
in / nin | In / not in a list |
contains | String contains |
startsWith / endsWith | String prefix / suffix |
isNull | Is (or is not) null |
Which operators are valid depends on the field's type. The gateway rejects an illegal
combination with a ZeitlosError.
Errors
Every failure throws a ZeitlosError with a machine-readable .code and, for gateway
errors, an HTTP .status.
import { ZeitlosError } from '@zeitlosapp/sdk';
try {
await client.from('posts').get(id);
} catch (err) {
if (err instanceof ZeitlosError && err.code === 'record_not_found') {
// 404
}
}| Code | When |
|---|---|
record_not_found | get, update or delete on an id that doesn't exist |
validation_failed | A value didn't match the field's type or constraints |
unique_violation | A unique field already holds that value |
forbidden | An access rule or the key's tier denied it |
invalid_filter | A filter used an operator the field doesn't support |
table_not_found | No such table in this project |
field_not_found | No such field on that table |
database_not_enabled | The project has no database yet |
quota_exceeded | A plan limit was hit |
network_error | The service couldn't be reached |
config_error | No URL or key available to the client |
Treat unknown codes generically — the list isn't closed.
SDK limitations
The SDK currently does not support any APIs to manage the schema of your database. Creating or altering tables and fields happens in the dashboard or through the MCP server.
There is no SQL API available.