Meta-framework SDKs

Next.js

Next.js SDK
Next.js SDK

Introduction

The Next.js SDK combines a client and a server SDK to provide configs to the browser, to server routes, and to SSR. It is intended to be used by Next.js web applications running on modern web browsers. All modern web browsers on popular platforms should be supported.

The minimum supported version of Next.js is 14.0.

Browser SDKs are tested on the latest versions of Chrome, Firefox, Safari, and Edge.

Telemetry collection within the browser uses Web Workers to aggregate and send telemetry data. If the SDK runs on older browsers without Web Workers support, config evaluation will continue to work but no telemetry data will be collected for that session.

Installation

The SDK can be installed from NPM: https://www.npmjs.com/package/@configdirector/nextjs-sdk

npm install --save @configdirector/nextjs-sdk

Configure the SDK

Set up the server instance to initialize at startup

The Next.js SDK maintains a singleton server SDK instance used in server routes and server side rendering (SSR). In order to register this instance at startup, you can make use of the Next.js instrumentation.ts file:

instrumentation.ts
export async function register() {
  const { register } = await import("@configdirector/nextjs-sdk/server");
  await register({
    // The server SDK key is a secret value, do not commit it to your source code repository.
    // In this example, we are assuming the environment variable CONFIGDIRECTOR_SERVER_SDK_KEY
    // will be populated at runtime with your server SDK key in the server environment
    serverSdkKey: process.env["CONFIGDIRECTOR_SERVER_SDK_KEY"],
  });
}

If you are using a version of Next.js older than 15, instrumentation is an experimental feature that must be enabled explicitly:

next.config.js
module.exports = {
  experimental: {
    instrumentationHook: true,
  },
};

Configure the client provider

The ConfigDirector hooks are only available within a ConfigDirectorProvider. The simplest approach is to wrap your application in a ConfigDirectorProvider in your layout:

app/layout.tsx
import { ConfigDirectorProvider } from "@configdirector/nextjs-sdk/server";
import type { ReactNode } from "react";

export default async function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ConfigDirectorProvider sdkKey={process.env["NEXT_PUBLIC_CONFIGDIRECTOR_CLIENT_SDK_KEY"]}>
          <main>{children}</main>
        </ConfigDirectorProvider>
      </body>
    </html>
  );
}

Additionally, you can configure the provider with a user context. In this example, we retrieve the userId from a cookie:

app/layout.tsx
import { ConfigDirectorProvider } from "@configdirector/nextjs-sdk/server";
import type { ReactNode } from "react";
import { cookies } from "next/headers";

export default async function RootLayout({ children }: { children: ReactNode }) {
  const userId = (await cookies()).get("userId")?.value;
  return (
    <html lang="en">
      <body>
        <ConfigDirectorProvider
          sdkKey={process.env["NEXT_PUBLIC_CONFIGDIRECTOR_CLIENT_SDK_KEY"]}
          context={{ userId }}>
          <main>{children}</main>
        </ConfigDirectorProvider>
      </body>
    </html>
  );
}

Additional configuration options

appName and appVersion

These metadata options allow you to provide your application's name and version. These values can be used in targeting rules conditionals. For example, if a certain feature should only be enabled starting with a certain version of your application.

instrumentation.ts
export async function register() {
  const { register } = await import("@configdirector/nextjs-sdk/server");
  await register({
    serverSdkKey: process.env["CONFIGDIRECTOR_SERVER_SDK_KEY"],
    metadata: {
      appName: "YOUR-APP-NAME",
      appVersion: "1.0.2",
    },
  });
}

The appName and appVersion are automatically propagated to the client SDK instance via the ConfigDirectorProvider RSC. However, if needed they can be overridden to a different value when configuring the provider as well:

app/layout.tsx
import { ConfigDirectorProvider } from "@configdirector/nextjs-sdk/server";
import type { ReactNode } from "react";

export default async function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ConfigDirectorProvider
          sdkKey={process.env["NEXT_PUBLIC_CONFIGDIRECTOR_CLIENT_SDK_KEY"]}
          appName="A-DIFFERENT-APP-NAME"
          appVersion="1.0.3">
          <main>{children}</main>
        </ConfigDirectorProvider>
      </body>
    </html>
  );
}

logger (server only)

By default, the SDK on the server side logs to the console and it is set to log warnings and errors only. You can configure a logger by either creating a ConfigDirector console logger with a different log level, or by implementing the ConfigDirectorLogger interface to provide your own logger. The interface can be used to create an adapter to another logging library.

Configure the ConfigDirector console logger to a different level:

instrumentation.ts
export async function register() {
  const { register } = await import("@configdirector/nextjs-sdk/server");
  await register({
    serverSdkKey: process.env["CONFIGDIRECTOR_SERVER_SDK_KEY"],
    logger: createConsoleLogger("info"),
  });
}

Implement your own logger adapter:

instrumentation.ts
export async function register() {
  const { register, ConfigDirectorLogger } = await import("@configdirector/nextjs-sdk/server");
  const myLogger: ConfigDirectorLogger = {
    debug: function (message: string, ...args: any): void {
      // your specific logging library implementation here
    },
    info: function (message: string, ...args: any): void {
      // your specific logging library implementation here
    },
    warn: function (message: string, ...args: any): void {
      // your specific logging library implementation here
    },
    error: function (message: string, ...args: any): void {
      // your specific logging library implementation here
    },
  };

  await register({
    serverSdkKey: process.env["CONFIGDIRECTOR_SERVER_SDK_KEY"],
    logger: myLogger,
  });
}

logLevel (client only)

The SDK on the client side logs to the browser console. You can adjust the ConfigDirector's SDK logging level for the client side via the logLevel option (defaults to warn):

app/layout.tsx
import { ConfigDirectorProvider } from "@configdirector/nextjs-sdk/server";
import type { ReactNode } from "react";

export default async function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ConfigDirectorProvider
          sdkKey={process.env["NEXT_PUBLIC_CONFIGDIRECTOR_CLIENT_SDK_KEY"]}
          logLevel="info">
          <main>{children}</main>
        </ConfigDirectorProvider>
      </body>
    </html>
  );
}

Additional server configuration

The register function accepts the same configuration values as the Node.js server SDK. You can refer to the Node.js SDK for a full list of those configuration options.

Retrieve config values

In your client components, retrieve a config value with the useConfigValue hook. On the server side, getConfigClient returns the global server instance of the client (an instance of the Node.js SDK).

Retrieving config values in client components:

YourComponent.tsx
"use client";

import { useConfigValue } from "@configdirector/nextjs-sdk/client";

function YourComponent() {
  const { value } = useConfigValue("my-config-key", false);

  return (<p>my-config-key: {value}</p>);
}

export default YourComponent;

Retrieving config values in server routes:

route.ts
import { getConfigClient } from "@configdirector/nextjs-sdk/server";

export async function GET() {
  const client = getConfigClient();
  const value = client.getValue("my-config-key", false);
  return Response.json({ "my-config-key": value });
}

SSR config evaluation

Evaluation of config values during server side rendering (SSR) utilizes the global server instance of the ConfigDirector Node.js client. That means there are no additional network requests that take place since the server SDK evaluates targeting rules locally for any given user context.

For SSR to work correctly, configs need to be made available to both, the client and the server, in the ConfigDirector dashboard.

Update the user context

The user context can be updated with the useContext hook:

YourComponent.tsx
"use client";

import { useConfigValue, useContext } from "@configdirector/nextjs-sdk/client";

function YourComponent() {
  const { value } = useConfigValue("my-config-key", false);
  const { updateContext } = useContext();

  useEffect(() => {
    updateContext({
      id: "654321",
      name: "Another User",
      traits: {
        region: "Australia",
      },
    });
  }, []);

  return <p>my-config-key: {value}</p>;
}

export default YourComponent;

On server routes, the user context is provided at evaluation time as the third argument to getValue. Unlike client SDKs, the server SDKs are able to evaluate targeting rules for the given user context locally without additional network calls.

route.ts
import { getConfigClient } from "@configdirector/nextjs-sdk/server";

export async function GET() {
  const client = getConfigClient();
  const value = client.getValue("my-config-key", false, {
    id: "654321",
    name: "Another User",
    traits: {
      region: "Australia",
    },
  });
  return Response.json({ "my-config-key": value });
}
Updating the context on the client side re-establishes a new connection to ConfigDirector servers with the new context. While the new connection is in flight, config values will continue to evaluate to the currently cached values from the prior user context.
Copyright © 2026