Skip to content

Feature flags

Typed flag client, React hooks, OpenFeature provider, codegen.

vb.flags connects to the realtime flag stream and serves up flag values without an extra HTTP round-trip per evaluation. Pairs with the Feature flags concept page.

await vb.flags.connect({
context: {
user: {
id: currentUser.id,
email: currentUser.email,
plan: currentUser.plan,
// any custom dims you target on (rules read them as `user.plan` etc.)
},
},
});

connect():

  1. Bulk-evaluates every flag against your context (POST /api/v1/flags/evaluate)
  2. Opens a WS to the __flags topic so updates push immediately
  3. Caches values in memory keyed by flag.key
  4. Re-evaluates every 60 s as well (pollIntervalMs, minimum 10 s; pollOnly: true skips the WS)

The evaluation request carries the signed-in session, so rules that target auth.* match for the current user (SDK 0.7.3+). If the server answers 401 (public evaluation turned off and no session), the cache keeps its last values and the session is left alone.

After connect, every read is synchronous (cache hit):

vb.flags.isEnabled("new-checkout"); // → boolean
vb.flags.getString("homepage-variant", "A"); // → "A" | "B" | "C"
vb.flags.getNumber("max-uploads", 5);
vb.flags.getJson("rollout-config", { steps: [] });
vb.flags.all(); // → Record<string, FlagValue>

The second arg is a default — returned when the flag is missing or the client isn’t connected yet.

When the user logs in / out / changes plan:

await vb.flags.setContext({ user: { id: newUser.id, plan: "paid" } });
// → re-bulks-evaluates and notifies subscribers
const off = vb.flags.on("change", (changedKeys) => {
for (const key of changedKeys) console.log("flag changed", key, vb.flags.all()[key]);
});
// off() to unsubscribe

The listener gets the keys whose values changed, so a UI can re-render only what reads them.

import { useFlag, useFlagString, useFlagNumber, useFlagJson } from "@vaultbase/sdk/flags/react";
function CheckoutButton() {
const isNew = useFlag(vb.flags, "new-checkout", false);
return isNew ? <NewCheckout /> : <OldCheckout />;
}
function Banner() {
const variant = useFlagString(vb.flags, "homepage-variant", "A");
return <div className={`banner-${variant}`}>…</div>;
}

Each hook takes the flags client first. It subscribes to vb.flags.on("change", ...) and re-renders only when its key is among the changed keys.

For apps already on the OpenFeature standard:

import { OpenFeature } from "@openfeature/web-sdk";
import { VaultbaseFlagsProvider } from "@vaultbase/sdk/openfeature";
OpenFeature.setProvider(new VaultbaseFlagsProvider(vb.flags));
const client = OpenFeature.getClient();
const enabled = await client.getBooleanValue("new-checkout", false);

Targeting context flows through OpenFeature’s targetingKey, which becomes user.id in the Vaultbase context; other fields pass through unchanged.

vb.flags.disconnect(); // closes the WS and stops polling; cached values stay

Don’t disconnect on every component unmount — vb.flags is a singleton on the client.

Flag keys in vb.flags are plain strings: a mistyped key compiles and returns the default. Run vb-flags to generate types from the server’s flag definitions and use them in your own code:

Terminal window
bunx vb-flags --url=https://api.example.com --admin-token=$ADMIN_TOKEN -o src/flags.gen.ts

--out / -o defaults to ./flags.gen.ts; --out - writes to stdout. The file exports FlagKey (a union of every flag key) and FlagTypes (key → value type; string flags with variations narrow to their values):

import type { FlagKey, FlagTypes } from "./flags.gen";
const key: FlagKey = "new-checkout"; // a typo here is a TS error
const variant = vb.flags.getString("homepage-variant", "A") as FlagTypes["homepage-variant"];

See Codegen + migrate CLI for the full CLI reference.