Loading...
Loading...
Flags SDK and Vercel Flags expert guidance. Use when declaring feature flags with flag(), wiring provider adapters (Vercel, Statsig, LaunchDarkly, PostHog, and others), managing flags with the vercel flags CLI, implementing the precompute pattern for static A/B tests, or integrating the Flags Explorer.
npx skill4agent add vercel/vercel-plugin flags-sdkflagsvercel flagsimport { flag } from 'flags/next';
export const exampleFlag = flag({
key: 'example-flag',
decide() { return false; },
});
const value = await exampleFlag();decideorigin@flags-sdk/vercelimport { flag } from 'flags/next';
import { vercelAdapter } from '@flags-sdk/vercel';
export const exampleFlag = flag({
key: 'example-flag',
adapter: vercelAdapter,
});Version note: The SDK is published as(renamed fromflags; that old name still appears in changelog history).@vercel/flags4.2.0+ accepts the adapter factory by reference (flags) and resolves it once per declaration. Older versions require calling it (adapter: vercelAdapter). The called form still works on new versions, so prefer the shorthand unless you're targetingadapter: vercelAdapter()< 4.2.0.flags
pnpm-lock.yamlpackage-lock.jsonyarn.lockbun.lockbpnpm addnpm installyarn addbun addflagspackage.json.vercel/vercel link.env.localFLAGS=flags.tslib/flags.tssrc/flags.ts@vercel/toolbarpackage.jsonapp/.well-known/vercel/flags/route.tspackage.jsonpnpm i flags @flags-sdk/vercelvercel flags add <flag-key> --kind boolean --description "<description>"Prerequisite: Thecommands require the Vercel CLI to be installed and authenticated. If the Vercel CLI is not installed, runvercel flags. For authentication or linking issues, follow thepnpm i -g vercelskill if it's already available. If it isn't, suggest the user install it withvercel-cli(don't auto-install it) and rely onnpx skills add vercel/vercel@vercel-cliin the meantime.vercel <command> --help
vercel flags add.vercelvercel linkvercel env pullFLAGSFLAGS_SECRET.env.localvercelAdapterflags.tsvercelAdapterimport { flag } from 'flags/next';
import { vercelAdapter } from '@flags-sdk/vercel';
export const myFlag = flag({
key: 'my-flag',
adapter: vercelAdapter,
});import { myFlag } from '../flags';
export default async function Page() {
const enabled = await myFlag();
return <div>{enabled ? 'Feature on' : 'Feature off'}</div>;
}pnpm i @vercel/toolbarnext.config.ts<VercelToolbar />app/.well-known/vercel/flags/route.tsvercel flags@flags-sdk/vercelFLAGSFLAGS_SECRETvercel flagsvercelAdapterflag()import { flag } from 'flags/next'; // or 'flags/sveltekit'
export const showBanner = flag<boolean>({
key: 'show-banner',
description: 'Show promotional banner',
defaultValue: false,
options: [
{ value: false, label: 'Hide' },
{ value: true, label: 'Show' },
],
decide() { return false; },
});identifydecideimport { dedupe, flag } from 'flags/next';
import type { ReadonlyRequestCookies } from 'flags';
interface Entities {
user?: { id: string };
}
const identify = dedupe(
({ cookies }: { cookies: ReadonlyRequestCookies }): Entities => {
const userId = cookies.get('user-id')?.value;
return { user: userId ? { id: userId } : undefined };
},
);
export const dashboardFlag = flag<boolean, Entities>({
key: 'new-dashboard',
identify,
decide({ entities }) {
if (!entities?.user) return false;
return ['user1', 'user2'].includes(entities.user.id);
},
});decideoriginimport { flag } from 'flags/next';
import { statsigAdapter } from '@flags-sdk/statsig';
export const myGate = flag({
key: 'my_gate',
adapter: statsigAdapter.featureGate((gate) => gate.value),
identify,
});| Parameter | Type | Description |
|---|---|---|
| | Unique flag identifier |
| | Resolves the flag value |
| | Fallback if |
| | Shown in Flags Explorer |
| | URL to manage the flag in provider dashboard |
| | Possible values, used for precompute + Flags Explorer |
| | Provider adapter implementing |
| | Returns evaluation context (entities) for |
identifydedupeimport { dedupe } from 'flags/next';
const identify = dedupe(({ cookies }) => {
return { user: { id: cookies.get('uid')?.value } };
});dedupeevaluate()flags/nextPromise.all()await myFlag()import { evaluate } from 'flags/next';
import { flagA, flagB } from '../flags';
// avoid: each await blocks the next, so the flags resolve sequentially
const a = await flagA();
const b = await flagB();
// avoid: parallel, but each flag is evaluated in isolation
const [a, b] = await Promise.all([flagA(), flagB()]);
// prefer: shares work across the batch
const [a, b] = await evaluate([flagA, flagB]);evaluate()Promise.all()evaluate()const [a, b] = await evaluate([flagA, flagB]);
const { a, b } = await evaluate({ a: flagA, b: flagB });getServerSidePropsawait evaluate([flagA, flagB], request)evaluate()getPrecomputedawait myFlag(code, flagGroup)bulkDecide@flags-sdk/vercelbulkDecideevaluate// app/.well-known/vercel/flags/route.ts
import { createFlagsDiscoveryEndpoint } from 'flags/next';
import { getProviderData } from '@flags-sdk/vercel';
import * as flags from '../../../../flags';
export const GET = createFlagsDiscoveryEndpoint(async () => {
return getProviderData(flags);
});mergeProviderDatagetProviderData// src/hooks.server.ts
import { createHandle } from 'flags/sveltekit';
import { FLAGS_SECRET } from '$env/static/private';
import * as flags from '$lib/flags';
export const handle = createHandle({ secret: FLAGS_SECRET, flags });node -e "console.log(crypto.randomBytes(32).toString('base64url'))"FLAGS_SECRETvercel env add FLAGS_SECRET production --sensitive --value <production-secret>
vercel env add FLAGS_SECRET preview --sensitive --value <preview-secret>
vercel env add FLAGS_SECRET development --value <development-secret>vc env pullprecompute(flagGroup)code/${code}/original-pathcodeawait myFlag(code, flagGroup)origindecide| Function | Purpose |
|---|---|
| Encrypt resolved flag values |
| Decrypt flag values |
| Encrypt flag definitions/metadata |
| Decrypt flag definitions |
| Encrypt toolbar overrides |
| Decrypt toolbar overrides |
FLAGS_SECRETimport { encryptFlagValues } from 'flags';
import { FlagValues } from 'flags/react';
async function ConfidentialFlags({ values }) {
const encrypted = await encryptFlagValues(values);
return <FlagValues values={encrypted} />;
}import { FlagValues, FlagDefinitions } from 'flags/react';
// Renders script tag with flag values for Flags Explorer
<FlagValues values={{ myFlag: true }} />
// Renders script tag with flag definitions for Flags Explorer
<FlagDefinitions definitions={{ myFlag: { options: [...], description: '...' } }} />flagsflags/reactflags/nextflags/sveltekit