惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
J
Java Code Geeks
量子位
腾讯CDC
C
Check Point Blog
小众软件
小众软件
IT之家
IT之家
I
InfoQ
Hugging Face - Blog
Hugging Face - Blog
Stack Overflow Blog
Stack Overflow Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
GbyAI
GbyAI
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
博客园_首页
S
SegmentFault 最新的问题
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
aimingoo的专栏
aimingoo的专栏
P
Proofpoint News Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Google DeepMind News
Google DeepMind News
T
Tailwind CSS Blog
Martin Fowler
Martin Fowler

Flags SDK Documentation

Global Config Bulk Evaluation Evaluation Context Precompute GrowthBook Hypertune PostHog Split Evaluation Context Quickstart Precompute Evaluation Context Quickstart Precompute GrowthBook Hypertune PostHog Split Proxy Dashboard Pages Dashboard Pages Marketing Pages Data Locality Providers LaunchDarkly Optimizely Reflag Statsig Server-side vs Client-side Flags as Code
Marketing Pages
Vercel · 2026-05-28 · via Flags SDK Documentation

Use feature flags on marketing pages.

This example shows how to use feature flags for marketing pages. Marketing pages are typically static, and served from a CDN at the edge.

When A/B testing on marketing pages it's important to avoid layout shift and jank, and to keep the pages static. At first glance this seems at odds with the dynamic nature of feature flags. This example shows how to keep a page static and serveable from the CDN even when running multiple A/B tests on the page.

The approach used to keep pages static even when using feature flags on them is described in more detail on the Precompute section. At a high level we use Proxy to rewrite the incoming request between static versions of the page. These static versions represent the different feature flag states and can be computed at build time or at request time. If they are computed at request time we can use Incremental Static Regeneration (ISR). Relying on ISR avoids the combinatory explosion which would otherwise increase the build time, while simulatenously allowing pages to stay cached after the first time they were requested.

Learn more about precompute

This example uses a random id stored in a cookie to target users. Next.js can't set cookies while rendering pages, so you must use Proxy to generate the random id and store it in a cookie.

This also allows the page to stay static as the page will never access cookies. Instead, the flags using cookies will be evaluated in Routing Functions and only the resulting flags will be available when rendering the page.

import { precompute } from 'flags/next';
import { type NextRequest, NextResponse } from 'next/server';
import { marketingFlags } from './flags';
import { getOrGenerateVisitorId } from './get-or-generate-visitor-id';

export async function marketingMiddleware(request: NextRequest) {
  // assign a cookie to the visitor
  const visitorId = await getOrGenerateVisitorId(
    request.cookies,
    request.headers,
  );

  // precompute the flags
  const code = await precompute(marketingFlags);

  // rewrite the page with the code and set the cookie
  return NextResponse.rewrite(
    new URL(`/examples/marketing-pages/${code}`, request.url),
    {
      headers: {
        // Set the cookie on the response
        'Set-Cookie': `marketing-visitor-id=${visitorId}; Path=/`,
        // Add a request header, so the page knows the generated id even
        // on the first-ever request which has no request cookie yet.
        //
        // This is later used by the getOrGenerateVisitorId function.
        'x-marketing-visitor-id': visitorId,
      },
    },
  );
}

The getOrGenerateVisitorId function generates a random id, or returns the one stored in a cookie if one already exists. The function is further deduplicated to ensure it generates the same id for the same request, even when called multiple times.

import { nanoid } from 'nanoid';
import { dedupe } from 'flags/next';
import type { ReadonlyHeaders, ReadonlyRequestCookies } from 'flags';
import type { NextRequest } from 'next/server';

const generateId = dedupe(async () => nanoid());

// This function is not deduplicated, as it is called with
// two different cookies objects, so it can not be deduplicated.
//
// However, the generateId function will always generate the same id for the
// same request, so it is safe to call it multiple times within the same runtime.
export const getOrGenerateVisitorId = async (
  cookies: ReadonlyRequestCookies | NextRequest['cookies'],
  headers: ReadonlyHeaders | NextRequest['headers'],
) => {
  // check cookies first
  const cookieVisitorId = cookies.get('marketing-visitor-id')?.value;
  if (cookieVisitorId) return cookieVisitorId;

  // check headers in case middleware set a cookie on the response, as it will
  // not be present on the initial request
  const headerVisitorId = headers.get('x-marketing-visitor-id');
  if (headerVisitorId) return headerVisitorId;

  // if no visitor id is found, generate a new one
  return generateId();
};

Having a reliable getOrGenerateVisitorId function means we can call it in Edge Runtime and in our flag's identify function and both will see the exact same id, even when no cookie was present initially.

// identify who is requesting the page
const identify = dedupe(
  async ({
    cookies,
  }: {
    cookies: ReadonlyRequestCookies;
  }): Promise<Entities> => {
    const visitorId = await getOrGenerateVisitorId(cookies);
    return { visitor: visitorId ? { id: visitorId } : undefined };
  },
);

export const marketingAbTest = flag<boolean, Entities>({
  key: 'marketing-ab-test-flag',
  // use identify to establish the evaluation context,
  // which will be passed as "entities" to the decide function
  identify,
  decide({ entities }) {
    if (!entities?.visitor) return false;
    return /^[a-n0-5]/i.test(entities.visitor.id);
  },
});

Learn more about identify

When a user visits the page for the first time they will not have the marketing-visitor-id cookie. Proxy will generate an id and store that in a cookie. However, this means the page will not see the generated cookie as it will only be supplied with the next request. This means a dynamic page would have no knowledge of the generated id.

To solve this issue the approach above also sets a x-marketing-visitor-id request header from Proxy, which holds the parsed or generated id. This allows the getOrGenerateVisitorId function to always see the id by either reading it from the cookie or the header. This works even when the id was freshly generated by Proxy and no cookie is present on the request.

This is only relevant when the underlying page is dynamic, as a static page can by definition not read any cookies or headers.

The example below shows the usage of two feature flags on a static page. These flags represent two A/B tests which you could be running simulatenously.