UNPKG

@rsc-kit/mcp

Version:

An MCP server over what an rsc-kit build decided: the routes, why each one is static or not, and what it costs the browser.

76 lines (58 loc) • 2.81 kB
# Feature flags > Vercel's Flags SDK runs unchanged — flags/next, without Next. Nothing to install from here. The [Flags SDK](https://flags-sdk.dev) is framework-agnostic at its core, and its Next integration — `flags/next`, the one with `flag()`, `dedupe()` and the adapters — needs one thing from Next: `next/headers`, for `headers()` and `cookies()`. Those exist here under the same names and with the same shapes, one object per request, which is what the SDK's per-request dedupe keys on. The build answers `next/headers` with them, so the SDK runs as written: ```sh bun add flags ``` ```ts title="src/flags.ts" import { flag, dedupe } from 'flags/next' const visitor = dedupe(async ({ cookies, headers }) => ({ id: cookies.get('visitor')?.value ?? 'anonymous', country: headers.get('x-vercel-ip-country') ?? headers.get('cf-ipcountry') ?? '', })) export const showBanner = flag<boolean, { id: string; country: string }>({ key: 'show-banner', identify: visitor, decide: ({ entities }) => entities?.country === 'GB', }) ``` ```tsx title="src/app/page.tsx" import { showBanner } from '../flags' export default async function Home() { const banner = await showBanner() return banner ? <Banner /> : null } ``` A flag reads the request, so the page that awaits one renders per visitor — the build says `headers() in run, cookies() in run stream per request` and stores the rest as a shell, given a `<Suspense>` or a `loading.tsx` above the read. That is the same line any `headers()` call earns; see [Static generation](/guides/static-generation). An adapter — Statsig, LaunchDarkly, Vercel's own — is the SDK's, configured the way its docs say. The discovery endpoint is a route handler in the shape a `route.ts` already has: ```ts title="src/app/.well-known/vercel/flags/route.ts" import { createFlagsDiscoveryEndpoint, getProviderData } from 'flags/next' import * as flags from '../../../../flags' export const GET = createFlagsDiscoveryEndpoint(async () => getProviderData(flags)) export const openapi = false ``` A test is not built, so it needs the alias too: one line in the test preload, which the scaffold ships. Without it `flags/next` finds Next's own `next/headers` — installed by some other app in a monorepo — and throws that `headers` was called outside a request scope. ```ts title="tests/preload.ts" mock.module('next/headers', () => import('@rsc-kit/core/request')) ``` A flag then evaluates inside `withRequest()`, the way anything that reads the request does in a test; see [Testing](/guides/testing). What does not carry over is `precompute()`: it is built on a Next middleware rewriting the url to a permutation, which is Next's routing. Read the flag in the page instead; a flag read under a boundary costs one streamed hole, not the page.