Overview

The @flagsync/nextjs-sdk integrates into Next.js applications with Vercel Flags for feature management and event tracking—ideal for SSR and static site generation workflows.

Installation

Install the SDK and required dependencies with your preferred package manager:

npm install @flagsync/nextjs-sdk flags

Quickstart

Set up the SDK in your Next.js application with these steps:

1

Initialize the Client

Initialize the FlagSync client singleton.

lib/flagsync.ts
import { createFlagSyncClient } from '@flagsync/nextjs-sdk';


export const client = createFlagSyncClient({

  sdkKey: process.env.FLAGSYNC_SDK_KEY!,

});
2

Define and Use a Feature Flag

Create a type-safe feature flag and use it in your Server Components.

import { flag } from 'flags/next';

import { client } from '@/lib/flagsync';

import { createStringFlagAdaptor } from '@flagsync/nextjs-sdk';


// Flag definition

export const myFlag = flag({

  key: 'my-flag',                           // Unique flag key

  identify: () => ({ key: 'user-123' }),    // Link flag to user context

  adapter: createStringFlagAdaptor(client), // Retrieves the flag with type safety

});

See User Context Identification for the recommended approach to building the context.

Initialization

Get Your SDK Key

Find your server-side SDK key in your workspace settings. Keep server-side keys private to protect flag rules.

Initialize the SDK

Initialize the FlagSync client singleton with your server-side SDK key:

lib/flagsync.ts
import { createFlagSyncClient } from '@flagsync/nextjs-sdk';


export const client = createFlagSyncClient({

  sdkKey: process.env.FLAGSYNC_SDK_KEY!,

});

Wait for Readiness

The SDK automatically initializes during the Next.js App Router lifecycle—no manual waiting is required for Server Components.

User Context Identification

Define the user context with a custom identify() function that returns an FsUserContext object. Pass this function to Vercel’s flag() function.

User contexts enable personalized flag evaluations via Individual Targeting and consistent experiences during Percentage Rollouts.

Ensure the key in FsUserContext is unique and persistent for accurate MAU tracking and consistent flag evaluations. See User Context Best Practices for details.

import { createIdentify } from '@flagsync/nextjs-sdk';

import { getFlagSyncUserContext } from '@/lib/flagsync.user-context.ts';


export const identify = createIdentify(getFlagSyncUserContext);
1

Create a Helper Function

Create a helper function to construct the user context from cookies and headers.

lib/flagsync.user-context.ts
import { nanoid } from 'nanoid';

import type { ReadonlyRequestCookies, ReadonlyHeaders } from 'flags';


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


export function getFlagSyncUserContext({ cookies, headers }) {

  const userId = getUserId(cookies);

  const visitorId = await getOrGenerateVisitorId(cookies);


  return {

    key: userId ?? visitorId,

    attributes: {

      region: headers.get('x-region'),

      userAgent: headers.get('user-agent')

    }

  };

};


function getUserId(cookies: ReadonlyRequestCookies) {

  return cookies.get('user-id')?.value;

}


async function getOrGenerateVisitorId(cookies: ReadonlyRequestCookies) {

  const visitorId = cookies.get('visitor-id')?.value;

  return visitorId ?? (await generateId());

}
The key is set using a persistent userId or visitorId from cookies, falling back to a generated ID with nanoid(). For proper MAU tracking and consistent flag evaluations, ensure this key is unique and persistent across requests—see User Context Best Practices.
2

Set Up Identification

Create identify with the helper, linking flags to user contexts.

lib/flagsync.ts
import { createIdentify } from '@flagsync/nextjs-sdk';

import { getFlagSyncUserContext } from '@/lib/flagsync.user-context.ts';


export const identify = createIdentify(getFlagSyncUserContext);
3

Set Cookies in Middleware (Optional)

Set user identification cookies in middleware to simplify context retrieval

Middleware is optional—user identification logic can be implemented directly in createIdentify() or getFlagSyncUserContext().

middleware.ts
import { NextRequest, NextResponse } from 'next/server';

import { nanoid } from 'nanoid';


const jwtSecret = new TextEncoder().encode('your-jwt-secret-key');


export async function middleware(request: NextRequest) {

  const response = NextResponse.next();


  const jwt = request.cookies.get('jwt')?.value;

  const visitorId = request.cookies.get('visitor-id')?.value


  let user;

  if (jwt) {

    const { payload } = await jwtVerify(jwt, jwtSecret);

    user = payload;

  }


  if (user?.userId) {

    response.cookies.set('user-id', user.userId, { maxAge: 60 * 60 * 24 * 7 });

  } else {

    response.cookies.set('visitor-id', visitorId ?? nanoid(), { maxAge: 60 * 60 * 24 * 365 });

  }


  return response;

}

Usage

Evaluate Flags

Evaluate flags in Server Components using the Vercel Flags flag function, which applies targeting rules, rollouts, and defaults for the user context:

An Impression is automatically registered when you evaluate the flag.

import { myFlag } from '@/app/dashboard/flags';


export default async function DashboardPage() {

  const value = await myFlag();


  return (

    <div>The value of {myFlag.key} is {value}</div>

  );

}

Track Events

Submit user actions with the track function:

api/checkout/route.js
import { cookies } from 'next/headers';

import { client, identify } from '@/lib/flagsync';

import { api } from '@/lib/api';



export async function POST(request) {

  const { product } = await request.json();


  const cookieStore = cookies(); // ReadonlyRequestCookies

  const headerStore = headers(); // ReadonlyHeaders


  const context = await identify({

    cookies: cookieStore,

    headers: headerStore

  });


  // Property event

  client.track(context, 'purchase-event', null, product);


  // Time the operation

  const t0 = Date.now();

  const order = await api.makePurchase(request);

  const receipt = await api.sendOrder(order)

  const t1 = Date.now()


  // Numeric event

  client.track(context, 'purchase-duration', t1 - t0);


  return Response.json({ success: true });

}

See Events: Tracking to learn about numeric and property events.

SDK Event Listeners

The SDK emits these events for SDK lifecycle management:

  • SDK_UPDATE: Emitted when flags are updated
  • SDK_READY: Emitted when the SDK is ready
  • ERROR: Emitted when an error occurs during initialization
import { FsEvent } from '@flagsync/js-sdk';


// Flag updates

client.on(FsEvent.SDK_UPDATE, () => {

  console.log(`Flags updated at ${new Date().toISOString()}`)

});

SDK_UPDATE does not fire if syncing is disabled.

Configuration

Configure the SDK with the FsConfig interface:

export interface FsConfig {

  sdkKey: string;

  sync?: {

    type?: 'stream' | 'poll' | 'off'; // Optional: Sync strategy

    pollRate?: number;                // Optional: Polling interval in seconds

  };

  tracking?: {

    impressions?: {

      maxQueueSize: number;           // Required: Max impressions queue size

      pushRate: number;               // Required: Impressions push rate

    };

    events?: {

      maxQueueSize: number;           // Required: Max events queue size

      pushRate: number;               // Required: Events push rate

    };

  };

  urls?: {

    sdk?: string;                     // Optional: SDK endpoint URL

  };

  logger?: Partial<ILogger>;          // Optional: Custom logger

  logLevel?: LogLevel;                // Optional: Logging level

  metadata?: Record<string, any>;     // Optional: Additional metadata

}

Custom Attributes

const context: FsUserContext = {

  key: 'user-123',

  attributes: {

    plan: 'premium',

    country: 'US',

    userType: 'enterprise'

  }

}

Ensure the key in FsUserContext is unique and persistent for accurate MAU tracking and consistent flag evaluations. See User Context Best Practices for details.

Flag Syncing

Configure flag update strategies with the sync object: stream, poll, or off.

By default, flag updates propagate in milliseconds via server-side events (SSE), ensuring the latest values are used in evaluations.

1

Stream (Default)

Stream updates via SSE—flag updates are reevaluated on the server and sent to the client:

createFlagSyncClient({

  sdkKey: 'your-sdk-key',

  sync: {

    type: 'stream' // Default

  }

});
2

Polling

Poll the server on an interval:

createFlagSyncClient({

  sdkKey: 'your-sdk-key',

  sync: {

    type: 'poll',

    pollRate: 60

  }

});
3

Off

Disable syncing:

createFlagSyncClient({

  sdkKey: 'your-sdk-key',

  sync: {

    type: 'off'

  }

});

Bootstrapping

Initialize the SDK with a set of bootstrap flags:

createFlagSyncClient({

  sdkKey: 'your-sdk-key',

  bootstrap: {

    'my-feature': true,

    'other-feature': false,

  },

});

Best Practices

  • Select a sync strategy (stream/poll/off) based on your application’s needs.
  • Follow User Context Identification for simplified context management.
  • Add user attributes for targeted feature rollouts.

Environment Variables

Set the following environment variable:

  • FLAGSYNC_SDK_KEY: Your server-side FlagSync SDK key (required)