Next.js
August 13, 2024
Bartosz Lewandowski

Flags in Next.js - how to add them and what are they used for?

Next.js is a popular React-based framework that enables the development of web applications with modern functionalities such as server-side rendering (SSR), static page generation (SSG) and advanced routing.

image

Next.js is a popular React-based framework that enables the development of web applications with modern functionalities such as server-side rendering (SSR), static page generation (SSG) and advanced routing. With these capabilities, Next.js has become the choice of many developers and companies around the world.

Flags are called mechanisms that allow us to control the enabling or disabling of particular features in an application without having to change the code and re-implement it. They can be used for AB experiments, incremental deployment of new features, or dynamic change of page content depending on business conditions.

The benefits of using flags in Next.js projects are numerous. First of all, flags allow for greater flexibility and control over the application, which is crucial, especially when working on large and complex systems. With flags it is possible to:

  1. Fast deployment of experiments: Ability to test different versions of features or content without having to change code and re-deploy the application.
  2. Manage features: Easily enable and disable individual features, making it easier for development teams to work together and safely deploy new features.
  3. Customization of content to the user: Dynamically change the content of the site depending on user preferences or specific business conditions.

The implementation of flags in Next.js, especially using the @vercel/flags/next module, provides a modern and efficient way to manage features in an application that is both flexible and scalable.

Basic configuration and explanation Next.js flags

First, make sure you have Node.js and npm or yarn installed, which are required to manage packages in your Next.js project. If you don't already have a Next.js project, you can easily create one using the npx create-next-app@latest command. Enter the name of the project and navigate to its directory.

Then install the @vercel/flags/next library. Use the npm install @vercel/flags command or yarn add @vercel/flags respectively, depending on which package manager you are using. This library allows you to manage function flags directly in your Next.js code.

The next step is to configure the FLAGS_SECRET secret key, which will be used by the SDK to read overridden functions set by the Vercel Toolbar. To do this, you need to generate the secret key using the crypto module:

node -e "console.log(crypto.randomBytes(32).toString('base64url'))"

The obtained key should be added as the FLAGS_SECRET environment variable in the .env.local file in the project's root directory.

Declaration of the first feature flag in Next.js application

To implement the first flag, we need to refer to the unstable_flag function, which is part of the @vercel/flags package. The name unstable indicates that the functionality is still in the experimental phase. This means that the functionality itself is not yet covered by semantic versioning. Vercel is still researching and planning further iterations of the feature, with the goal of optimizing and customizing it for users.

1export const showHolidayBanner = flag<boolean>({
2  key: 'holiday-baner',
3  async decide() {
4    return false;
5  },
6  origin: 'https://example.com/flags/holiday-baner/',
7  description: 'Show holiday banner',
8  defaultValue: false,
9  options: [
10    { value: false, label: 'Hide' },
11    { value: true, label: 'Show' },
12  ],
13});

Here are the basic parameters used when declaring a function flag:

  • key (string): The key of the function flag.
  • decide (function): The function that resolves the value of the function flag.
  • defaultValue (Optional) (any): The default value that will be used if the `decide` function returns `undefined` or reports an error.
  • description (Optional) (string): Description of the function flag.
  • origin (Optional) (string): The URL where the function flag can be managed.
  • options (Optional) ({ label?: string, value: any }[]): Possible values that the function flag can reference, displayed in the Vercel Toolbar.

The decide function can play different roles depending on the business logic you want to implement. It can return values based on environment variables, use asynchronous queries to the API, or rely on context conditions.

Case 1: Returning a static value

A simple case where the decide function always returns a specific value, such as false.

1async decide() {
2  return false;
3}

Case 2: Value based on environment variable

1async decide() {
2  return process.env.HOLIDAY_BANNER_ENABLED === '1';
3}

Case 3: Using JavaScript's built-in API to decide the value of a flag

1async decide() {
2  try {
3    const response = await fetch('https://api.example.com/feature-flags/holiday-baner');
4    const data = await response.json();
5    return data.enabled;
6  } catch (error) {
7    console.error('Error fetching feature flag:', error);
8    return false; 
9  }
10}

Case 4: Context conditions

1async decide() {
2  const userCountry = cookies().get('user-country').value;
3  return userCountry === 'US'; // Only US users see the Christmas banner
4}

Using the feature flag

To use the feature flag in a Next.js project, we first need to import it in the appropriate file, and then apply its value in the code.

1import { showHolidayBanner } from '../flags';
2
3export default async function Page() {
4  const isBannerVisible = await showHolidayBanner();
5
6  return (
7    <div>
8      {isBannerVisible ? (
9        <p>Holiday banner is displayed!</p>
10      ) : (
11        <p>Holiday banner is hidden.</p>
12      )}
13    </div>
14  );
15}

Precomputing feature flags

Precomputing flags is an approach that allows feature flags to be calculated in advance at the middleware stage. Before passing these values to components, which reduces loading delays and improves application performance, especially for statically generated pages (SSG) and pages with dynamic routing.

1//flags.ts
2import { unstable_flag as flag } from '@vercel/flags/next';
3
4export const showHolidayBanner = flag<boolean>({
5  key: 'holiday-banner',
6  decide: () => false,
7  origin: 'https://example.com/flags/holiday-banner/',
8  description: 'Show holiday banner',
9  defaultValue: false,
10  options: [
11    { value: false, label: 'Hide' },
12    { value: true, label: 'Show' },
13  ],
14});
15
16export const precomputeFlags = [showHolidayBanner] as const;

In the middleware, we calculate the values of the flags and pass them to the pages and components using URLs rewritten in the right way.

1// middleware.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { unstable_precompute as precompute } from '@vercel/flags/next';
4import { precomputeFlags } from './flags';
5
6export const config = { matcher: ['/'] };
7
8export async function middleware(request: NextRequest) {
9  const code = await precompute(precomputeFlags);
10  const nextUrl = new URL(
11    `/${code}${request.nextUrl.pathname}${request.nextUrl.search}`,
12    request.url,
13  );
14  return NextResponse.rewrite(nextUrl, { request });
15}

To access the values of the flags calculated in the middleware, import the necessary flags and the passed code from the URL in your component.

1// app/[code]/page.tsx
2import { precomputeFlags, showHolidayBanner } from '../../flags';
3
4export default async function Page({ params }: { params: { code: string } }) {
5  const holidayBanner = await showHolidayBanner(params.code, precomputeFlags);
6
7  return (
8    <div>
9      {holidayBanner ? <p>Holiday banner is displayed!</p> : <p>Welcome to our website!</p>}
10    </div>
11  );
12}

Precomputing flags has several key advantages:

  • Reduction of loading delays: Calculations are performed in advance, eliminating the need to perform them dynamically in real time.
  • Prevention of flickering and layout shift: Flag values are calculated and embedded in the URL before the page is loaded, preventing content display issues.
  • Optimization for static pages: Precomputed flags can be used in precomputed page generation (SSG) scenarios, allowing static pages to contain dynamic content without performance loss.

Integration of flags with Vercel toolbar

Vercel Toolbar is a development tool provided by Vercel that allows teams to easily manage and test application features in real time. With Vercel Toolbar, you can override the values of flags, allowing you to dynamically enable and disable specific features without having to modify your application code and re-implement it.

To use Vercel Toolbar with Next.js, there are a few steps to follow:

1. First, we need to install the @vercel/toolbar package, using npm:

npm install @vercel/toolbar

2. Next, configure the Vercel Toolbar in the Next.js configuration file (next.config.mjs):

1/** @type {import('next').NextConfig} */
2import withVercelToolbar from '@vercel/toolbar/plugins/next';
3const nextConfig = {};
4
5export default withVercelToolbar()(nextConfig);

3. After configuring the package, we need to import the Vercel Toolbar into the main layout file of our application so that it is available on all subpages.

1import { VercelToolbar } from '@vercel/toolbar/next';
2
3const inter = Inter({ subsets: ['latin'] });
4
5export default function RootLayout({
6  children,
7}: Readonly<{
8  children: React.ReactNode;
9}>) {
10  return (
11    <html lang="en">
12      <body className={inter.className}>
13        {children} <VercelToolbar />
14      </body>
15    </html>
16  );
17}

In order for Vercel Toolbar to get information about function flags in your application, you need to add a corresponding API endpoint. Vercel Toolbar will make an authenticated request to this endpoint to retrieve the definitions of your application's feature flags. It is important to place this endpoint in such a path app/.well-known/vercel/flags/route.ts

1import { type ApiData, verifyAccess } from '@vercel/flags';
2import { unstable_getProviderData as getProviderData } from '@vercel/flags/next';
3import { NextResponse, type NextRequest } from 'next/server';
4import * as flags from '../../../../flags';
5
6export const runtime = 'edge';
7export const dynamic = 'force-dynamic';
8
9export async function GET(request: NextRequest) {
10  const access = await verifyAccess(request.headers.get('Authorization'));
11  if (!access) return NextResponse.json(null, { status: 401 });
12
13  return NextResponse.json<ApiData>(getProviderData(flags));
14}

Connecting project with Vercel

To use the Vercel Toolbar and manage feature flags, you must publish your application on Vercel. To do so:

  1. Connect your repository to your Vercel account.
  2. Log in to the project using the command: vercel link
  3. Run the application: npm run dev

Using the Vercel Toolbar in Next.js application

Now you have access to the Vercel Toolbar, where you can manage the function flags you have declared.

  1. On your application's page, click the Vercel icon in the lower right corner to open the Vercel Toolbar.
  2. In the Vercel Toolbar, go to the "Feature Flags" section. There you will see all available feature flags, their current values, and the details you define. From there, you can dynamically enable and disable flags, overriding their values ​​and watching your app change in real time.

With Vercel Toolbar you can efficiently manage application functions and test new features without having to modify the code and re-deploy the project.

Summary

Feature flags are a powerful tool for managing and deploying new features in Next.js applications. They allow you to control, test, and activate features without having to modify your code or redeploy your application. Using feature flags in Next.js with Vercel provides flexibility and agility in managing your evolving application.

Using the @vercel/flags/next module, you can declare feature flags in your Next.js code. The unstable_flag function allows you to define a flag by assigning it a key, a decision function, a default value, a description, and other options. The precomputing flags functionality allows you to precompute flag values ​​in the middleware, which improves application performance and reduces loading delays. This way, users see relevant content without having to wait for the flag values ​​to be dynamically recalculated.

Vercel provides a developer tool called Vercel Toolbar, which allows you to dynamically manage feature flags. Adding a feature flag API endpoint in Next.js allows Vercel Toolbar to retrieve and manage flag definitions. The endpoint must be authenticated and return detailed flag information, which enables dynamic management of these features.

Using feature flags in Next.js with Vercel is an effective approach to managing application features, allowing for smooth and secure rollouts of new functionality without having to re-deploy the application. This allows for rapid response to changing user needs and market conditions, while providing better control and reliability of the application.

Recent blog