Reference

@vercel/flags API Reference

Learn about available APIs when supporting feature flags in your applications
Table of Contents

Feature flags are available in Beta on all plans

The @vercel/flags package provides convenience methods, components, and types for supporting feature flag overrides.

  1. Install the @vercel/flags package:
pnpm
yarn
npm
pnpm i @vercel/flags
  1. Import the methods you require from the @vercel/flags package:
import { ... } from '@vercel/flags';

Reports the value of a feature flag to Vercel so it can show up in Runtime Logs and be used with Web Analytics custom server-side events. Returns undefined.

ParameterTypeDescription
keystringKey of the feature flag
valueanyValue of the feature flag
import { reportValue } from '@vercel/flags';
 
reportValue('summer-sale', true);

A method for encrypting data (Flag definitions, overrides, and values). Returns a Promise.

ParameterTypeDescription
dataObjectData to be encrypted
secret (Optional)stringThe secret being used to encrypt. Defaults to process.env.FLAGS_SECRET

Here is an example of encrypting flag values to be used by the Vercel Toolbar.

Next.js (/app)
Next.js (/pages)
app/page.tsx
import { encrypt } from '@vercel/flags';
import { FlagValues, type FlagValuesType } from '@vercel/flags/react';
 
async function ConfidentialFlagValues({ values }: { values: FlagValuesType }) {
  const encryptedFlagValues = await encrypt(values);
  return <FlagValues values={encryptedFlagValues} />;
}
 
export function Page() {
  const values = { exampleFlag: true };
  return (
    <div>
      {/* Some other content */}
      <Suspense fallback={null}>
        <ConfidentialFlagValues values={values} />
      </Suspense>
    </div>
  );
}

A method for decrypting encrypted data. Returns a Promise.

ParameterTypeDescription
encryptedDatastringData to be decrypted
secret (Optional)stringThe secret being used to encrypt data. Defaults to process.env.FLAGS_SECRET

The decrypt method's primary use case is decrypting the data stored inside the vercel-flag-overrides cookie. It's also used by the Vercel Toolbar to handle your feature flag data.

Next.js (/app)
Next.js (/pages)
app/getFlags.ts
import { FlagOverridesType, decrypt } from '@vercel/flags';
import { type NextRequest } from 'next/server';
import { cookies } from 'next/headers';
 
async function getFlags(request: NextRequest) {
  const overrideCookie = cookies().get('vercel-flag-overrides')?.value;
  const overrides = overrideCookie
    ? await decrypt<FlagOverridesType>(overrideCookie)
    : {};
 
  const flags = {
    exampleFlag: overrides?.exampleFlag ?? false,
  };
 
  return flags;
}

A method for verifying whether a request to your application's flags endpoint was made by the Vercel Toolbar. You can use verifyAccess to keep your endpoint private. Returns a Promise with a true or false value.

ParameterTypeDescription
authHeader.stringAuthorization header to check
secret (Optional)stringThe secret being used to encrypt data. Defaults to process.env.FLAGS_SECRET
Next.js (/app)
Next.js (/pages)
app/.well-known/vercel/flags/route.ts
import { NextResponse, type NextRequest } from "next/server";
import { verifyAccess, type ApiData } from "@vercel/flags";
 
export async function GET(request: NextRequest) {
  const access = await verifyAccess(request.headers.get('Authorization'));
  if (!access) return NextResponse.json(null, { status: 401 });
 
  const apiData: ApiData = /* ... */
 
  return NextResponse.json<ApiData>(apiData);
}

A safe version of JSON.stringify that escapes the resulting output to prevent XSS attacks. Returns string.

ParameterTypeDescription
valueanyA valid JSON object to convert
replacer (Optional)function | ArrayA replacer function or Array
space (Optional)string | numberSpecifies the spacing in the output
import { safeJsonStringify } from '@vercel/flags';
 
safeJsonStringify({ markup: '<html></html>' });
// '{"markup":"\\u003chtml>\\u003c/html>"}'

The @vercel/flags package also providers convenience methods for getting flag definition data from certain providers. Each of these functions returns a Promise.

Get LaunchDarkly flag definitions. Accepts an options object with the following keys.

Options keyTypeDescription
apiKeystringLaunchDarkly API key
environmentstringLaunchDarkly environment
projectKeystringLaunchDarkly project key
Next.js (/app)
Next.js (/pages)
app/.well-known/vercel/flags/route.ts
import { verifyAccess, type ApiData } from '@vercel/flags';
import { getLaunchDarklyData } from '@vercel/flags/providers/launchdarkly';
import { NextResponse, type NextRequest } from 'next/server';
 
export async function GET(request: NextRequest) {
  const access = await verifyAccess(request.headers.get('Authorization'));
  if (!access) return NextResponse.json(null, { status: 401 });
 
  const launchDarklyData = await getLaunchDarklyData({
    apiKey: process.env.LAUNCHDARKLY_API_KEY,
    projectKey: process.env.LAUNCHDARKLY_PROJECT_KEY,
    environment: process.env.LAUNCHDARKLY_ENVIRONMENT,
  });
 
  return NextResponse.json<ApiData>(launchDarklyData);
}

Get Split flag definitions. Accepts an options object with the following keys.

Options keyTypeDescription
adminApiKeystringSplit admin API key
workspaceIdstringSplit workspace ID
organizationIdstringSplit organization ID
environmentIdstringSplit environment ID
Next.js (/app)
Next.js (/pages)
app/.well-known/vercel/flags/route.ts
import { verifyAccess, type ApiData } from '@vercel/flags';
import { getSplitData } from '@vercel/flags/providers/split';
import { NextResponse, type NextRequest } from 'next/server';
 
export async function GET(request: NextRequest) {
  const access = await verifyAccess(request.headers.get('Authorization'));
  if (!access) return NextResponse.json(null, { status: 401 });
 
  const splitData = await getSplitData({
    adminApiKey: process.env.SPLIT_ADMIN_API_KEY,
    environmentId: process.env.SPLIT_ENVIRONMENT_ID,
    organizationId: process.env.SPLIT_ORG_ID,
    workspaceId: process.env.SPLIT_WORKSPACE_ID,
  });
 
  return NextResponse.json<ApiData>(splitData);
}

Get StatSig flag definitions. Accepts an options object with the following keys.

Options keyTypeDescription
consoleApiKeystringStatsig console API key
projectIdstringStatSig project ID
Next.js (/app)
Next.js (/pages)
app/.well-known/vercel/flags/route.ts
import { verifyAccess, type ApiData } from '@vercel/flags';
import { getStatsigData } from '@vercel/flags/providers/statsig';
import { NextResponse, type NextRequest } from 'next/server';
 
export async function GET(request: NextRequest) {
  const access = await verifyAccess(request.headers.get('Authorization'));
  if (!access) return NextResponse.json(null, { status: 401 });
 
  const statsigData = await getStatsigData({
    consoleApiKey: process.env.STATSIG_CONSOLE_API_KEY,
    projectId: process.env.STATSIG_PROJECT_ID,
  });
 
  return NextResponse.json<ApiData>(statsigData);
}

Get Optimizely flag definitions. Accepts an options object with the following keys.

Options keyTypeDescription
apiKeystringOptimizely API key
projectIdstringOptimizely project ID
Next.js (/app)
Next.js (/pages)
app/.well-known/vercel/flags/route.ts
import { verifyAccess, type ApiData } from '@vercel/flags';
import { getOptimizelyData } from '@vercel/flags/providers/optimizely';
import { NextResponse, type NextRequest } from 'next/server';
 
export async function GET(request: NextRequest) {
  const access = await verifyAccess(request.headers.get('Authorization'));
  if (!access) return NextResponse.json(null, { status: 401 });
 
  const optimizelyData = await getOptimizelyData({
    projectId: process.env.OPTIMIZELY_PROJECT_ID,
    apiKey: process.env.OPTIMIZELY_API_KEY,
  });
 
  return NextResponse.json<ApiData>(optimizelyData);
}

Get Hypertune flag definitions. Accepts an options object with the following keys.

Options keyTypeDescription
tokenstringThe HYPERTUNE_ADMIN_TOKEN
Next.js (/app)
Next.js (/pages)
app/.well-known/vercel/flags/route.ts
import { verifyAccess, type ApiData } from '@vercel/flags';
import { getHypertuneData } from '@vercel/flags/providers/hypertune';
import { NextResponse, type NextRequest } from 'next/server';
 
export async function GET(request: NextRequest) {
  const access = await verifyAccess(request.headers.get('Authorization'));
  if (!access) return NextResponse.json(null, { status: 401 });
 
  const hypertuneData = await getHypertuneData({
    token: process.env.HYPERTUNE_ADMIN_TOKEN,
  });
 
  return NextResponse.json<ApiData>(hypertuneData);
}

It is possible to integrate feature flag providers that Vercel does not export a dedicated provider function for.

To integrate any feature flag provider:

  1. First, use the provider's REST API to fetch their feature flags and return them in the expected format through the Flags API Endpoint. This makes Vercel Toolbar aware of the feature flags defined in your flag provider.
  2. Then, make your application respect the override cookie set by Vercel Toolbar.

As well as convenience methods, the @vercel/flags package provides types for the different entities.

type JsonArray = ReadonlyArray<JsonValue>;
export type JsonValue =
  | string
  | boolean
  | number
  | null
  | JsonArray
  | { [key: string]: JsonValue };
 
interface FlagOptionType {
  value: JsonValue;
  label?: string;
}
 
export interface FlagDefinitionType {
  options?: FlagOptionType[];
  /**
   * The URL where the feature flag can be managed.
   */
  origin?: string;
  description?: string;
}
/**
 * Definitions of a feature flags.
 *
 * Definitions are data like the description, available options, or its origin.
 */
export type FlagDefinitionsType = Record<string, FlagDefinitionType>;
 
/**
 * Values of feature flags.
 *
 * This record consists of key-value pairs of flag keys and the value they resolved to.
 */
export type FlagValuesType = Record<string, JsonValue>;
 
/**
 * Overrides of feature flags.
 *
 * This record consists of key-value pairs of flag keys and the override to be used for them.
 */
export type FlagOverridesType = Record<string, JsonValue>;
 
/**
 * Data flag providers can return to integrate with the toolbar.
 */
export type ProviderData = {
  definitions: FlagDefinitionsType;
  hints?: { key: string; text: string }[];
};
 
/**
 * Data returned by the .well-known/vercel/flags API Route which the toolbar understands.
 */
export type ApiData = {
  /**
   * Metadata about your application's feature flags
   */
  definitions?: FlagDefinitionsType;
  /**
   * Hints show up in the toolbar. They are meant to be used in case loading
   * data from your flag provider fails. For example when the provider fails to
   * responed or the configuration is invalid due to a missing environment variable.
   */
  hints?: ProviderData['hints'];
  /**
   * Sets the encryption mode for the vercel-flag-overrides cookie
   * - when set to "encrypted" the toolbar will store encrypted overrides
   * - when set to "plaintext" the toolbar will store plaintext overrides
   */
  overrideEncryptionMode: 'encrypted' | 'plaintext';
};

If you are using React, you can use the FlagValues and FlagDefinitions components. These abstract you from needing to manually render script tags. These components handle setting the correct data attributes and escaping any data to prevent XSS.

Pass flag data into the FlagValues component with the values prop.

Next.js (/app)
Next.js (/pages)
app/page.tsx
import { FlagValues } from '@vercel/flags/react';
 
export function Page() {
  return (
    <div>
      {/* Some other content */}
      <FlagValues values={{ exampleFlag: true }} />
    </div>
  );
}

To keep your flags confidential, encrypt the input:

Next.js (/app)
Next.js (/pages)
app/page.tsx
import { encrypt } from '@vercel/flags';
import { FlagValues, type FlagValuesType } from '@vercel/flags/react';
 
async function ConfidentialFlagValues({ values }: { values: FlagValuesType }) {
  const encryptedFlagValues = await encrypt(values);
  return <FlagValues values={encryptedFlagValues} />;
}
 
export function Page() {
  const values = { exampleFlag: true };
  return (
    <div>
      {/* Some other content */}
      <Suspense fallback={null}>
        <ConfidentialFlagValues values={values} />
      </Suspense>
    </div>
  );
}
PropTypeDescription
valuesFlagValuesTypeThe feature flag values to expose to the Vercel Toolbar

Pass flag data into the FlagDefinitions component with the definitions prop.

Next.js (/app)
Next.js (/pages)
app/page.tsx
import { FlagDefinitions } from '@vercel/flags/react';
 
export function Page() {
  const flagDefinitions = {
    exampleFlag: {
      options: [{ value: false }, { value: true }],
      origin: 'https://example.com/flag/exampleFlag',
      description: 'This is an example flag.',
    },
  };
  return (
    <div>
      {/* Some other content */}
      <FlagDefinitions definitions={flagDefinitions} />
    </div>
  );
}

To keep your flags confidential, encrypt the input:

Next.js (/app)
Next.js (/pages)
app/page.tsx
import { encrypt, type FlagDefinitionsType } from '@vercel/flags';
import { FlagDefinitions } from '@vercel/flags/react';
 
async function ConfidentialFlagDefinitions({
  definitions,
}: {
  definitions: FlagDefinitionsType;
}) {
  const encryptedFlagDefinitions = await encrypt(definitions);
  return <FlagDefinitions values={encryptedFlagDefinitions} />;
}
 
export function Page() {
  const flagDefinitions = {
    exampleFlag: {
      options: [{ value: false }, { value: true }],
      origin: 'https://example.com/flag/exampleFlag',
      description: 'This is an example flag.',
    },
  };
  return (
    <div>
      {/* Some other content */}
      <Suspense fallback={null}>
        <ConfidentialFlagDefinitions values={flagDefinitions} />
      </Suspense>
    </div>
  );
}
PropTypeDescription
definitionsFlagDefinitionsTypeThe feature flag definitions to expose to the Vercel Toolbar
Last updated on November 4, 2024