Skip to content

Codegen + migrate CLI

vb-types, vb-flags, vb-migrate — generate typed schemas + sync collections across environments.

The SDK ships three CLIs:

CLIWhat it does
vb-typesPull the live admin’s collection schema → emit Schema for typed Vaultbase usage
vb-flagsPull the live admin’s flag definitions → emit a typed-keys module
vb-migrateSync collection schemas across environments (dev → staging → prod)

All three take --url <baseUrl> and --admin-token <admin-jwt>; vb-types and vb-migrate can read a snapshot file with --schema <file> instead.

Terminal window
bunx vb-types \
--url https://admin.example.com \
--admin-token $ADMIN_TOKEN \
--out src/vaultbase.gen.ts

Output:

// AUTO-GENERATED by `vb-types`. Do not edit.
// Regenerate via: vb-types --url https://admin.example.com --admin-token $ADMIN_TOKEN --out src/vaultbase.gen.ts
export interface PostsRecord {
id: string;
created: number;
updated: number;
title: string;
body?: string | null;
author: string; // relation → users
published_at?: number | null;
}
export interface PostsCreate {
title: string;
body?: string | null;
author: string;
published_at?: string | number | null;
}
export type PostsUpdate = Partial<PostsCreate>;
export interface UsersRecord {
id: string;
created: number;
updated: number;
email: string;
email_verified: number;
totp_enabled: number;
is_anonymous: number;
name?: string | null;
}
export type Schema = {
posts: { record: PostsRecord; create: PostsCreate; update: PostsUpdate };
users: { record: UsersRecord; create: UsersCreate; update: UsersUpdate };
// …
};

Each collection gets <Name>Record, <Name>Create and <Name>Update, named after the collection in PascalCase. The header repeats the command that made the file, with the admin token shown as $ADMIN_TOKEN.

An auth collection’s record carries the fields the server returns for a user: email, and email_verified, totp_enabled and is_anonymous as numbers (0 or 1). Its Create type takes email and password. (SDK 0.7.3; earlier releases typed a verified: boolean the server never sends.)

Field types:

FieldReadWrite
text, email, url, editor, relation, colorstringstring
numbernumbernumber
boolbooleanboolean
datenumber (Unix seconds)string | number (ISO string or Unix seconds)
autodatenumbernot writable
vectornumber[]number[]
geoPoint{ lat: number; lng: number }same
selectits values as a union (an array when multiple)same
filestring (string[] when multiple)same
jsonunknownunknown

A field that isn’t required is optional and T | null: the server returns an unset field as null, and writing null clears it.

Use it:

import { Vaultbase } from "@vaultbase/sdk";
import type { Schema } from "./vaultbase.gen";
const vb = new Vaultbase<Schema>({ baseUrl: "..." });
await vb.collection("posts").create({
title: "hi", // ✓
fakeField: 1, // ✗ TS error
});
const list = await vb.collection("posts").list();
list.data[0]?.title; // ← string, inferred

A singleton collection’s entry carries singleton: true (SDK 0.7.0), which is what vb.singleton() accepts:

settings: { record: SettingsRecord; create: never; update: SettingsUpdate; singleton: true };

Its record’s fields are all optional and T | null, required or not, since the record starts empty.

const s = await vb.singleton("settings").get(); // typed as SettingsRecord

Re-run the CLI after every schema change. Wire it into your build:

package.json
{
"scripts": {
"codegen:vb": "vb-types --url $VB_URL --admin-token $VB_TOKEN --out src/vaultbase.gen.ts",
"build": "bun codegen:vb && bun build src/index.ts"
}
}
Terminal window
bunx vb-flags \
--url https://admin.example.com \
--admin-token $ADMIN_TOKEN \
--out src/flags.gen.ts

Generates a TS module that augments @vaultbase/sdk so flag reads are typed by key + variation:

import "./flags.gen";
vb.flags.isEnabled("new-checkout"); // ✓
vb.flags.getString("homepage-variant", "A"); // ↑ "A" | "B" | "C" inferred
vb.flags.isEnabled("typo"); // ✗ TS error

See Feature flags for usage.

Move schema (collections + fields + rules) between environments without hand-editing JSON.

Terminal window
# 1. Pull a snapshot from prod
bunx vb-migrate pull \
--url https://prod.example.com \
--admin-token $PROD_TOKEN \
--out prod-snapshot.json
# 2. Diff against staging — what would change?
bunx vb-migrate diff \
--url https://staging.example.com \
--admin-token $STAGING_TOKEN \
--schema prod-snapshot.json
# → collections to create (+), to update (~), and only on staging (-)
# 3. Apply (additive: only creates missing collections and fields)
bunx vb-migrate apply \
--url https://staging.example.com \
--admin-token $STAGING_TOKEN \
--schema prod-snapshot.json \
--mode additive --yes
# 4. Or sync: also updates existing collections to match. Nothing is deleted;
# collections only on staging are listed with "-" and left alone.
bunx vb-migrate apply --mode sync --yes --schema prod-snapshot.json --url ...

The same operations are available as functions:

import {
pullSnapshot,
diffSnapshot,
applySnapshot,
} from "@vaultbase/sdk/migrate";
const snap = await pullSnapshot({
url: "https://prod.example.com",
adminToken: process.env.PROD_TOKEN!,
});
const diff = await diffSnapshot(snap, {
url: "https://staging.example.com",
adminToken: process.env.STAGING_TOKEN!,
});
// diff has an entry per collection, "unchanged" ones included
if (diff.some((d) => d.kind !== "unchanged")) {
await applySnapshot(snap, {
url: "https://staging.example.com",
adminToken: process.env.STAGING_TOKEN!,
mode: "additive",
});
}

Use this in CI to fail builds when staging drifts from prod.

prod-snapshot.json:

{
"version": 1,
"generated_at": "2026-10-19T18:08:33.510Z",
"collections": [
{
"name": "posts",
"type": "base",
"fields": [ … ],
"list_rule": null,
"view_rule": "@request.auth.id != ''",
"create_rule": "",
"update_rule": "owner = @request.auth.id",
"delete_rule": "owner = @request.auth.id"
},
…
]
}

Versioned on disk so future SDK upgrades can read older snapshots.

Pulled snapshots carry all five rules; null is public. A rule left out of a hand-written snapshot is admin-only ("") when it creates a collection, and left as it is when sync applies it to an existing one. See Schema migrations.

.github/workflows/db-sync.yml
- name: Pull prod snapshot
run: bunx vb-migrate pull --url $PROD_URL --admin-token $PROD_TOKEN --out snap.json
- name: Verify staging matches prod
run: |
DIFF=$(bunx vb-migrate diff --schema snap.json --url $STAGING_URL --admin-token $STAGING_TOKEN)
echo "$DIFF"
# Drift = anything to create or update, or a collection only on staging.
if echo "$DIFF" | grep -qE '^ [+~-] '; then
echo "Staging drift detected"
exit 1
fi