Vercel Flags SDK
Vercel's Flags SDK is the flags-as-code layer for Next.js and SvelteKit. Its OpenFeature adapter accepts any OpenFeature provider — including Lucerna's — so Gates plugs into flag() declarations without a native adapter.
Setup
bash
pnpm add flags @flags-sdk/openfeature @lucerna-dev/gates-openfeature @lucerna-dev/gates-node @openfeature/server-sdkDeclare the adapter once and use it in every flag:
ts
// flags.ts
import { flag } from "flags/next";
import { createOpenFeatureAdapter } from "@flags-sdk/openfeature";
import { OpenFeature } from "@openfeature/server-sdk";
import { LucernaProvider } from "@lucerna-dev/gates-openfeature";
const lucernaAdapter = createOpenFeatureAdapter(async () => {
await OpenFeature.setProviderAndWait(
new LucernaProvider({ serverKey: process.env.LUCERNA_SERVER_KEY! }),
);
return OpenFeature.getClient();
});
export const showNewBilling = flag<boolean>({
key: "new_billing_page",
defaultValue: false,
identify: ({ cookies }) => ({ targetingKey: cookies.get("uid")?.value }),
adapter: lucernaAdapter.booleanValue(),
});Then read it in a server component or route handler:
tsx
import { showNewBilling } from "./flags";
export default async function Page() {
const newBilling = await showNewBilling();
return newBilling ? <NewBilling /> : <ClassicBilling />;
}Experiments
Declare experiment flags as flag<string> — the variant name comes back through getStringValue, and the exposure is recorded server-side on the read:
ts
export const checkoutTest = flag<string>({
key: "checkout_test",
defaultValue: "control",
identify: ({ cookies }) => ({ targetingKey: cookies.get("uid")?.value }),
adapter: lucernaAdapter.stringValue(),
});Notes
identifysupplies the evaluation context per request;targetingKeybecomes the GatesuserId, so decisions stay sticky per user. See the context mapping.- The Flags SDK evaluates each declared flag separately. Concurrent reads for the same flag and identity share one request, and
remoteCacheTtlMscan memoize across sequential reads in a warm process — see requests and caching. - The provider is stateless and Edge-runtime compatible: pure
fetch, no timers, no Node APIs.