Skip to content

Records

vb.collection("name") returns a typed accessor over a single collection. Every method maps 1-1 to a server endpoint and returns the same shape the REST API does.

const posts = vb.collection<Post>("posts");
await posts.list({ filter: "published = true", sort: "-created", perPage: 50 });
await posts.get("p1");
await posts.create({ title: "hi", body: "<p>…</p>" });
await posts.update("p1", { title: "renamed" });
await posts.delete("p1");
for await (const r of posts.iterate({ filter: "published = true" })) { /* … */ }
await vb.collection("posts").list({
page: 1,
perPage: 30,
filter: 'status = "live" && @request.auth.id = author',
sort: "-created,title",
expand: "author,tags",
fields: "id,title,author.name",
skipTotal: true, // skip COUNT(*) for huge tables
});

Returns:

{
data: T[];
page: number;
perPage: number;
totalItems: number; // -1 when skipTotal
totalPages: number; // -1 when skipTotal
}
for await (const post of vb.collection<Post>("posts").iterate({
filter: 'tags ?= "tutorial"',
perPage: 100,
})) {
console.log(post.title);
}

Backed by repeated list calls until the server stops returning a full page.

const post = await vb.collection<Post>("posts").get("p1");

Returns 404 → throws VaultbaseError with kind: "not_found".

const post = await vb.collection<Post>("posts").create({
title: "Hello",
body: "<p>World</p>",
author: "u_42",
});
// post.id is the freshly generated UUID; created/updated set by the server.

Validation failures throw VaultbaseError with kind: "validation" and a details: { fieldName: message } map. Match codes pre-1.0:

  • 400 → bad request
  • 403 → rule denied
  • 404 → collection / parent record missing
  • 409 → unique violation, optimistic-concurrency mismatch
  • 422 → schema validation
const updated = await vb.collection<Post>("posts").update("p1", {
title: "Renamed",
});

PATCH semantics — only the fields you send are touched.

ETag/If-Match concurrency runs automatically (see Errors + ETags): the SDK caches the ETag from prior reads and attaches If-Match on the next mutation. Override with:

// Skip the precondition entirely:
await posts.update("p1", { title: "x" }, { ifMatch: false });
// Use an explicit tag:
await posts.update("p1", { title: "x" }, { ifMatch: "W/\"42\"" });

If the server’s ETag has moved, the SDK throws VaultbaseError with kind: "precondition_failed" and the current etag attached so you can retry against the latest state.

await vb.collection("posts").delete("p1");

Same ifMatch semantics as update. Returns null on success.

Filters live in the same expression language as collection rules. See API rules for the full grammar. For ergonomic, injection-safe construction use the vb.q tag:

const term = req.query.q;
const filter = vb.q`title ~ ${term} && status = ${"live"} && deleted = ${false}`;
// → 'title ~ "hello" && status = "live" && deleted = false'
await vb.collection("posts").list({ filter });
InterpolationEncoded as
string"…" (escaped)
numberbare; rejects NaN/Infinity
booleantrue/false
nullnull
Datequoted ISO string
Array(…) comma-joined — pairs with ?= / ?~
field("name")bare identifier (validated)

vb.q ALWAYS quotes strings — to interpolate a column name use the field() escape:

const sortable = vb.field("title");
const filter = vb.q`${sortable} ~ ${"hello"}`;
// → 'title ~ "hello"'
const ac = new AbortController();
posts.list({ signal: ac.signal });
ac.abort(); // → throws kind: "aborted"
posts.list({ requestKey: "search-suggest" });
posts.list({ requestKey: "search-suggest" });
// → first request is auto-cancelled when the second starts (defaultAutoCancel)

Disable auto-cancel via requestKey: null per-call or defaultAutoCancel: false at construction.

When you generate the Schema type via vb-types, every collection accessor becomes typed:

const vb = new Vaultbase<Schema>({ baseUrl: "..." });
await vb.collection("posts").create({
title: "hi", // ✓
body: "<p>…</p>", // ✓
fakeField: 1, // ✗ TS error
});
const list = await vb.collection("posts").list({ filter: "published = true" });
list.data[0].title; // string — inferred

See Codegen + migrate CLI.