flags-sdk
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFlags SDK
Flags SDK
The Flags SDK ( npm package) is a feature flags toolkit for Next.js and SvelteKit. It turns each feature flag into a callable function, works with any flag provider via adapters, and keeps pages static using the precompute pattern.
flags- Docs: https://flags-sdk.dev
- Repo: https://github.com/vercel/flags
Flags SDK( npm包)是面向Next.js和SvelteKit的功能标志工具集。它将每个功能标志转化为可调用的函数,通过适配器支持任意标志提供方,并使用预计算模式保持页面静态化。
flagsCore Concepts
核心概念
Flags as Code
标志即代码
Each flag is declared as a function — no string keys at call sites:
ts
import { flag } from 'flags/next';
export const exampleFlag = flag({
key: 'example-flag',
decide() { return false; },
});
// Usage: just call the function
const value = await exampleFlag();每个标志都声明为函数,调用处无需使用字符串key:
ts
import { flag } from 'flags/next';
export const exampleFlag = flag({
key: 'example-flag',
decide() { return false; },
});
// Usage: just call the function
const value = await exampleFlag();Server-Side Evaluation
服务端评估
Evaluate flags server-side to avoid layout shift, keep pages static, and maintain confidentiality. Use routing middleware + precompute to serve static variants from CDN.
在服务端评估标志可以避免布局偏移、保持页面静态化、保障数据保密性。使用路由中间件+预计算从CDN返回静态变体页面。
Adapter Pattern
适配器模式
Adapters replace and on a flag declaration, enabling provider-agnostic flags:
decideorigints
import { flag } from 'flags/next';
import { statsigAdapter } from '@flags-sdk/statsig';
export const myGate = flag({
key: 'my_gate',
adapter: statsigAdapter.featureGate((gate) => gate.value),
identify,
});适配器会替换标志声明中的和属性,实现与提供方无关的标志定义:
decideorigints
import { flag } from 'flags/next';
import { statsigAdapter } from '@flags-sdk/statsig';
export const myGate = flag({
key: 'my_gate',
adapter: statsigAdapter.featureGate((gate) => gate.value),
identify,
});Declaring Flags
声明标志
Basic Flag
基础标志
ts
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; },
});ts
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; },
});Flag with Evaluation Context
带评估上下文的标志
Use to establish who the request is for; receives the entities:
identifydecidets
import { 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);
},
});使用定义请求对应的主体,方法可以接收该实体信息:
identifydecidets
import { 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);
},
});Flag with Adapter
带适配器的标志
ts
import { flag } from 'flags/next';
import { vercelAdapter } from '@flags-sdk/vercel';
export const exampleFlag = flag({
key: 'example-flag',
adapter: vercelAdapter(),
});ts
import { flag } from 'flags/next';
import { vercelAdapter } from '@flags-sdk/vercel';
export const exampleFlag = flag({
key: 'example-flag',
adapter: vercelAdapter(),
});Key Parameters
核心参数
| 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 |
| 参数名 | 类型 | 描述 |
|---|---|---|
| | 唯一的标志标识符 |
| | 解析返回标志值 |
| | |
| | 在Flags Explorer中展示的描述信息 |
| | 提供方控制台中管理该标志的URL |
| | 可选值列表,用于预计算和Flags Explorer展示 |
| | 实现了 |
| | 返回供 |
Dedupe
Dedupe
Wrap shared functions (especially ) in to run them once per request:
identifydedupets
import { dedupe } from 'flags/next';
const identify = dedupe(({ cookies }) => {
return { user: { id: cookies.get('uid')?.value } };
});Note: is not available in Pages Router.
dedupe将共享函数(尤其是)用包裹,使其每次请求仅执行一次:
identifydedupets
import { dedupe } from 'flags/next';
const identify = dedupe(({ cookies }) => {
return { user: { id: cookies.get('uid')?.value } };
});注意:在Pages Router中不可用。
dedupeFlags Explorer Setup
Flags Explorer 配置
Next.js (App Router)
Next.js (App Router)
ts
// app/.well-known/vercel/flags/route.ts
import { getProviderData, createFlagsDiscoveryEndpoint } from 'flags/next';
import * as flags from '../../../../flags';
export const GET = createFlagsDiscoveryEndpoint(async () => {
return getProviderData(flags);
});ts
// app/.well-known/vercel/flags/route.ts
import { getProviderData, createFlagsDiscoveryEndpoint } from 'flags/next';
import * as flags from '../../../../flags';
export const GET = createFlagsDiscoveryEndpoint(async () => {
return getProviderData(flags);
});With External Provider Data
对接外部提供方数据
ts
import { getProviderData, createFlagsDiscoveryEndpoint } from 'flags/next';
import { getProviderData as getStatsigProviderData } from '@flags-sdk/statsig';
import { mergeProviderData } from 'flags';
import * as flags from '../../../../flags';
export const GET = createFlagsDiscoveryEndpoint(async () => {
return mergeProviderData([
getProviderData(flags),
getStatsigProviderData({
consoleApiKey: process.env.STATSIG_CONSOLE_API_KEY,
projectId: process.env.STATSIG_PROJECT_ID,
}),
]);
});ts
import { getProviderData, createFlagsDiscoveryEndpoint } from 'flags/next';
import { getProviderData as getStatsigProviderData } from '@flags-sdk/statsig';
import { mergeProviderData } from 'flags';
import * as flags from '../../../../flags';
export const GET = createFlagsDiscoveryEndpoint(async () => {
return mergeProviderData([
getProviderData(flags),
getStatsigProviderData({
consoleApiKey: process.env.STATSIG_CONSOLE_API_KEY,
projectId: process.env.STATSIG_PROJECT_ID,
}),
]);
});SvelteKit
SvelteKit
ts
// 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 });ts
// 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 });FLAGS_SECRET
FLAGS_SECRET
Required for precompute and Flags Explorer. Must be 32 random bytes, base64-encoded:
sh
node -e "console.log(crypto.randomBytes(32).toString('base64url'))"Store as env var. On Vercel: then .
FLAGS_SECRETvc env add FLAGS_SECRETvc env pull预计算和Flags Explorer必需的配置项。必须是32随机字节的base64编码值:
sh
node -e "console.log(crypto.randomBytes(32).toString('base64url'))"存储为环境变量。在Vercel上执行:,然后执行。
FLAGS_SECRETvc env add FLAGS_SECRETvc env pullPrecompute Pattern (Overview)
预计算模式(概述)
Use precompute to keep pages static while using feature flags. Middleware evaluates flags and encodes results into the URL via rewrite. The page reads precomputed values instead of re-evaluating.
High-level flow:
- Declare flags and group them in an array
- Call in middleware, get a
precompute(flagGroup)stringcode - Rewrite request to
/${code}/original-path - Page reads flag values from :
codeawait myFlag(code, flagGroup)
For full implementation details, see framework-specific references:
- Next.js: See references/nextjs.md — covers proxy middleware, precompute setup, ISR, generatePermutations, multiple groups
- SvelteKit: See references/sveltekit.md — covers reroute hook, middleware, precompute setup, ISR, prerendering
使用预计算可以在使用功能标志的同时保持页面静态化。中间件评估标志并通过重写将结果编码到URL中。页面直接读取预计算值,无需重新评估。
高层流程:
- 声明标志并将其分组到数组中
- 在中间件中调用,获取
precompute(flagGroup)字符串code - 将请求重写到
/${code}/original-path - 页面从中读取标志值:
codeawait myFlag(code, flagGroup)
完整实现细节请参考对应框架的文档:
- Next.js: 查看 references/nextjs.md — 包含代理中间件、预计算配置、ISR、generatePermutations、多分组等内容
- SvelteKit: 查看 references/sveltekit.md — 包含 reroute 钩子、中间件、预计算配置、ISR、预渲染等内容
Custom Adapters
自定义适配器
Create an adapter factory returning an object with and :
origindecidets
import type { Adapter } from 'flags';
export function createMyAdapter(/* options */) {
return function myAdapter<ValueType, EntitiesType>(): Adapter<ValueType, EntitiesType> {
return {
origin(key) {
return `https://my-provider.com/flags/${key}`;
},
async decide({ key }): Promise<ValueType> {
// evaluate against your provider
return false as ValueType;
},
};
};
}创建适配器工厂函数,返回包含和属性的对象:
origindecidets
import type { Adapter } from 'flags';
export function createMyAdapter(/* options */) {
return function myAdapter<ValueType, EntitiesType>(): Adapter<ValueType, EntitiesType> {
return {
origin(key) {
return `https://my-provider.com/flags/${key}`;
},
async decide({ key }): Promise<ValueType> {
// evaluate against your provider
return false as ValueType;
},
};
};
}Encryption Functions
加密函数
For keeping flag data confidential in the browser (used by Flags Explorer):
| Function | Purpose |
|---|---|
| Encrypt resolved flag values |
| Decrypt flag values |
| Encrypt flag definitions/metadata |
| Decrypt flag definitions |
| Encrypt toolbar overrides |
| Decrypt toolbar overrides |
All use by default. Example:
FLAGS_SECRETtsx
import { encryptFlagValues } from 'flags';
import { FlagValues } from 'flags/react';
async function ConfidentialFlags({ values }) {
const encrypted = await encryptFlagValues(values);
return <FlagValues values={encrypted} />;
}用于在浏览器中保障标志数据的保密性(供Flags Explorer使用):
| 函数名 | 用途 |
|---|---|
| 加密解析后的标志值 |
| 解密标志值 |
| 加密标志定义/元数据 |
| 解密标志定义 |
| 加密工具栏覆盖配置 |
| 解密工具栏覆盖配置 |
所有函数默认使用。示例:
FLAGS_SECRETtsx
import { encryptFlagValues } from 'flags';
import { FlagValues } from 'flags/react';
async function ConfidentialFlags({ values }) {
const encrypted = await encryptFlagValues(values);
return <FlagValues values={encrypted} />;
}React Components
React 组件
tsx
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: '...' } }} />tsx
import { FlagValues, FlagDefinitions } from 'flags/react';
// 渲染包含标志值的script标签,供Flags Explorer使用
<FlagValues values={{ myFlag: true }} />
// 渲染包含标志定义的script标签,供Flags Explorer使用
<FlagDefinitions definitions={{ myFlag: { options: [...], description: '...' } }} />References
参考资料
Detailed framework and provider guides are in separate files to keep context lean:
- references/nextjs.md: Next.js quickstart, App Router, Pages Router, middleware/proxy, precompute, dedupe, dashboard pages, marketing pages, suspense fallbacks
- references/sveltekit.md: SvelteKit quickstart, hooks setup, toolbar, precompute with reroute + middleware, dashboard pages, marketing pages
- references/providers.md: All provider adapters — Vercel, Edge Config, Statsig, LaunchDarkly, PostHog, GrowthBook, Hypertune, Flagsmith, Reflag, Split, Optimizely, OpenFeature, and custom adapters
- references/api.md: Full API reference for ,
flags,flags/react, andflags/nextflags/sveltekit
为了保持内容精简,详细的框架和提供方指南放在单独文件中:
- references/nextjs.md:Next.js快速入门、App Router、Pages Router、中间件/代理、预计算、dedupe、仪表盘页面、营销页面、suspense 降级方案
- references/sveltekit.md:SvelteKit快速入门、hooks配置、工具栏、基于reroute+中间件的预计算、仪表盘页面、营销页面
- references/providers.md:所有提供方适配器说明 — Vercel、Edge Config、Statsig、LaunchDarkly、PostHog、GrowthBook、Hypertune、Flagsmith、Reflag、Split、Optimizely、OpenFeature以及自定义适配器
- references/api.md:、
flags、flags/react和flags/next的完整API参考flags/sveltekit