Skip to content

Batch

Atomic multi-op transactions over the records API.

vb.batch() returns a fluent builder for /api/v1/batch. Up to 100 ops in a single request, executed inside one SQLite transaction — either every op succeeds or every op rolls back.

  • Atomicity: insert + update + delete with one conditional rollback
  • Latency: one round-trip instead of N
  • Determinism: server holds a transaction lock, so concurrent writers can’t interleave with your sequence
const r = await vb.batch()
.create("posts", { title: "first" })
.create("posts", { title: "second" })
.update("posts", "p_42", { published: true })
.delete("posts", "p_99")
.list("posts", { filter: "published = true", perPage: 5 })
.run();
// r is BatchResult — array of per-op outcomes in submit order
r[0].status; // 201 — create
r[0].body; // { id: "...", title: "first", ... }
r[3].status; // 204 — delete
r[4].body.data; // post[]

If any op of a batch with writes fails (a validation error, a rule denial, a missing record or collection), the whole transaction rolls back and run() throws a VaultbaseError for that op’s status (validation for 422, auth for 403, conflict for 409, server with status otherwise). Its message names the op, counting from 0:

try {
await vb.batch()
.create("posts", { title: "ok" })
.update("posts", "missing-id", { title: "x" })
.run();
} catch (e) {
// e.kind === "server", e.data.status === 404
// e.message === "Batch failed at request 1: Record not found"
// nothing was committed, not even the create
}

A batch of only reads (get / list) isn’t a transaction: it returns each op’s status, so a missing record is a 404 entry in the result and the other reads still answer.

batch.create<K>(collection: K, body: SchemaCreate<K>);
batch.update<K>(collection: K, id: string, body: SchemaUpdate<K>);
batch.delete(collection: string, id: string);
batch.get(collection: string, id: string);
batch.list<K>(collection: K, options?: ListOptions);

The generic K extends keyof Schema ties body types to your codegen schema. Without codegen the args fall back to unknown/AnyRecord.

Batch ops respect the same per-collection rules as the underlying REST endpoints. The caller’s auth (token in vb.client.authStore) is the auth context for every op in the batch. Admin tokens bypass rules; user tokens have rules evaluated per op.

CapDefault
Ops per batch100
Per-op timeoutinherits the standard request timeout

Exceeding 100 returns 422 before the transaction starts.

import { isVaultbaseError } from "@vaultbase/sdk";
try {
await vb.batch().create("posts", {}).run();
} catch (e) {
if (isVaultbaseError(e) && e.data.kind === "validation") {
e.data.details; // { field: message } for the op that failed
}
throw e;
}
  • Streaming reads — use vb.collection().iterate() instead
  • Cross-collection queries that need a JOIN — write a view collection with raw SQL
  • Long-running jobs — use hooks · routes · cron or the queue worker subsystem