{"id":18463937,"url":"https://github.com/unleash/unleash-client-nextjs","last_synced_at":"2025-04-05T07:05:06.220Z","repository":{"id":65380944,"uuid":"590991945","full_name":"Unleash/unleash-client-nextjs","owner":"Unleash","description":"Unleash SDK for Next.js","archived":false,"fork":false,"pushed_at":"2025-03-26T13:43:16.000Z","size":593,"stargazers_count":28,"open_issues_count":2,"forks_count":9,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-29T06:07:29.238Z","etag":null,"topics":["ab-testing","abtesting","continuous-delivery","continuous-deployment","experimentation","feature-flags","hacktoberfest","javascript","nextjs","node","node-js","sdk","server-rendering","server-side-rendering","typescript","unleash","vercel"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Unleash.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-19T17:27:00.000Z","updated_at":"2025-03-26T13:43:24.000Z","dependencies_parsed_at":"2023-06-28T14:32:53.799Z","dependency_job_id":"b210737b-6ddb-433c-8e78-389a3849be52","html_url":"https://github.com/Unleash/unleash-client-nextjs","commit_stats":null,"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Unleash%2Funleash-client-nextjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Unleash%2Funleash-client-nextjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Unleash%2Funleash-client-nextjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Unleash%2Funleash-client-nextjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Unleash","download_url":"https://codeload.github.com/Unleash/unleash-client-nextjs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299831,"owners_count":20916190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ab-testing","abtesting","continuous-delivery","continuous-deployment","experimentation","feature-flags","hacktoberfest","javascript","nextjs","node","node-js","sdk","server-rendering","server-side-rendering","typescript","unleash","vercel"],"created_at":"2024-11-06T09:08:25.117Z","updated_at":"2025-04-05T07:05:06.197Z","avatar_url":"https://github.com/Unleash.png","language":"TypeScript","readme":"# Unleash Next.js SDK\n\nThis package allows easy integration of [Unleash](https://github.com/unleash/unleash) feature flags in a [Next.js](https://nextjs.org/) application.\n\n## Setup\n\n### Installation\n\nTo install, simply run:\n\n```sh\nnpm install @unleash/nextjs\n# or\nyarn add @unleash/nextjs\n# or\npnpm add @unleash/nextjs\n```\n\nThere is an [`./example`](./example) project that you can [deploy to Vercel](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FUnleash%2Funleash-client-nextjs%2Ftree%2Fmain%2Fexample) or [edit in CodeSandbox](https://codesandbox.io/s/github/Unleash/unleash-client-nextjs/tree/main/example).\n\n### Environment variables\n\nThis package will attempt to load configuration from\n[Next.js Environment variables](https://nextjs.org/docs/basic-features/environment-variables).\n\nWhen using Unleash **client-side**, with `\u003cFlagProvider /\u003e` or `getFrontendFlags()` configure:\n\n- `NEXT_PUBLIC_UNLEASH_FRONTEND_API_URL`. URL should end with `/api/frontend` or `/proxy`\n- `NEXT_PUBLIC_UNLEASH_FRONTEND_API_TOKEN` [client-side API token](https://docs.getunleash.io/reference/api-tokens-and-client-keys#front-end-tokens)\n  if you're using the [front-end API](https://docs.getunleash.io/reference/front-end-api),\n  or a [proxy client key](https://docs.getunleash.io/reference/api-tokens-and-client-keys#proxy-client-keys)\n  if you're using a [proxy](https://docs.getunleash.io/reference/unleash-proxy)\n- Using [Edge](https://docs.getunleash.io/reference/unleash-edge) is the same as using the frontend API, so you'll need a FRONTEND_API_TOKEN, and your URL should end with `/api/frontend`.\n\nIf using **server-side** (SSR, SSG, API), using `getDefinitions()` and `evaluateFlags()`, set:\n\n- `UNLEASH_SERVER_API_URL` of you instance. URL should end with `/api`\n- `UNLEASH_SERVER_API_TOKEN` [server-side API client token](https://docs.getunleash.io/reference/api-tokens-and-client-keys#client-tokens)\n\n#### Detailed explanation\n\n| Prefixable     | Variable                     | Default                                                   |\n| -------------- | ---------------------------- | --------------------------------------------------------- |\n| `NEXT_PUBLIC_` | `UNLEASH_SERVER_API_URL`     | `http://localhost:4242/api`                               |\n| `NEXT_PUBLIC_` | `UNLEASH_FRONTEND_API_URL`   | `\u003c(NEXT_PUBLIC_)UNLEASH_SERVER_API_URL\u003e/frontend`         |\n| **No**         | `UNLEASH_SERVER_API_TOKEN`   | `default:development.unleash-insecure-api-token`          |\n| **No**         | `UNLEASH_SERVER_INSTANCE_ID` | undefined                                                 |\n| `NEXT_PUBLIC_` | `UNLEASH_FRONTEND_API_TOKEN` | `default:development.unleash-insecure-frontend-api-token` |\n| `NEXT_PUBLIC_` | `UNLEASH_APP_NAME`           | `nextjs`                                                  |\n\nIf you plan to use configuration in the browser, add `NEXT_PUBLIC_` prefix.\nIf both are defined and available, private variable takes priority.\nYou can use both to have different values on client-side and server-side.\n\n---\n\n💡 **Usage with GitLab's feature flags**: To use this SDK with [GitLab Feature Flags](https://docs.gitlab.com/ee/operations/feature_flags.html), use `UNLEASH_SERVER_INSTANCE_ID` instead of `UNLEASH_SERVER_API_TOKEN` to [authorize with GitLab's service](https://docs.gitlab.com/ee/operations/feature_flags.html#get-access-credentials).\n\n---\n\n# Usage\n\n## A). **App router**\n\nThis package is ready for server-side use with [App Router](https://nextjs.org/docs/app/building-your-application/routing).\n\nRefer to [`./example/README.md#App-router`](https://github.com/Unleash/unleash-client-nextjs/tree/main/example#app-router) for an implementation example.\n\n```tsx\nimport { cookies } from \"next/headers\";\nimport { evaluateFlags, flagsClient, getDefinitions } from \"@unleash/nextjs\";\n\nconst getFlag = async () =\u003e {\n  const cookieStore = cookies();\n  const sessionId =\n    cookieStore.get(\"unleash-session-id\")?.value ||\n    `${Math.floor(Math.random() * 1_000_000_000)}`;\n\n  const definitions = await getDefinitions({\n    fetchOptions: {\n      next: { revalidate: 15 }, // Cache layer like Unleash Proxy!\n    },\n  });\n\n  const { toggles } = evaluateFlags(definitions, {\n    sessionId,\n  });\n  const flags = flagsClient(toggles);\n\n  return flags.isEnabled(\"nextjs-example\");\n};\n\nexport default async function Page() {\n  const isEnabled = await getFlag();\n\n  return (\n    \u003cp\u003e\n      Feature flag is{\" \"}\n      \u003cstrong\u003e\n        \u003ccode\u003e{isEnabled ? \"ENABLED\" : \"DISABLED\"}\u003c/code\u003e\n      \u003c/strong\u003e\n      .\n    \u003c/p\u003e\n  );\n}\n```\n\n## B). Middleware\n\nIt's possible to run this SDK in Next.js Edge Middleware. This is a great use case for A/B testing, where you can transparently redirect users to different pages based on a feature flag. Target pages can be statically generated, improving performance.\n\nRefer to [`./example/README.md#Middleware`](https://github.com/Unleash/unleash-client-nextjs/tree/main/example#middleware) for an implementation example.\n\n## C). Client-side only - simple use case and for development purposes (CSR)\n\nFastest way to get started is to connect frontend directly to Unleash.\nYou can find out more about direct [Front-end API access](https://docs.getunleash.io/reference/front-end-api) in our documentation,\nincluding a guide on how to [setup a client-side SDK key](https://docs.getunleash.io/how-to/how-to-create-api-tokens).\n\nImportant: Hooks and provider are only available in `@unleash/nextjs/client`.\n\n```tsx\nimport type { AppProps } from \"next/app\";\nimport { FlagProvider } from \"@unleash/nextjs/client\";\n\nexport default function App({ Component, pageProps }: AppProps) {\n  return (\n    \u003cFlagProvider\u003e\n      \u003cComponent {...pageProps} /\u003e\n    \u003c/FlagProvider\u003e\n  );\n}\n```\n\nWith `\u003cFlagProvider /\u003e` in place you can now use hooks like: `useFlag`, `useVariant`, or `useFlagsStatus` to block rendering until flags are ready.\n\n```jsx\nimport { useFlag } from \"@unleash/nextjs/client\";\n\nconst YourComponent = () =\u003e {\n  const isEnabled = useFlag(\"nextjs-example\");\n\n  return \u003c\u003e{isEnabled ? \"ENABLED\" : \"DISABLED\"}\u003c/\u003e;\n};\n```\n\nOptionally, you can configure `FlagProvider` with the `config` prop. It will take priority over environment variables.\n\n```jsx\n\u003cFlagProvider\n  config={{\n    url: \"http://localhost:4242/api/frontend\", // replaces NEXT_PUBLIC_UNLEASH_FRONTEND_API_URL\n    clientKey: \"\u003cFrontend_API_token\u003e\", // replaces NEXT_PUBLIC_UNLEASH_FRONTEND_API_TOKEN\n    appName: \"nextjs\", // replaces NEXT_PUBLIC_UNLEASH_APP_NAME\n\n    refreshInterval: 15, // additional client configuration\n    // see https://github.com/Unleash/unleash-proxy-client-js#available-options\n  }}\n\u003e\n```\n\nIf you only plan to use [Unleash client-side React SDK](https://github.com/Unleash/proxy-client-react) now also works with Next.js. Check documentation there for more examples.\n\n## D). Static Site Generation, optimized performance (SSG)\n\nWith same access as in the client-side example above you can resolve Unleash feature flags when building static pages.\n\n```tsx\nimport {\n  flagsClient,\n  getDefinitions,\n  evaluateFlags,\n  getFrontendFlags,\n  type IVariant,\n} from \"@unleash/nextjs\";\nimport type { GetStaticProps, NextPage } from \"next\";\n\ntype Data = {\n  isEnabled: boolean;\n  variant: IVariant;\n};\n\nconst ExamplePage: NextPage\u003cData\u003e = ({ isEnabled, variant }) =\u003e (\n  \u003c\u003e\n    Flag status: {isEnabled ? \"ENABLED\" : \"DISABLED\"}\n    \u003cbr /\u003e\n    Variant: {variant.name}\n  \u003c/\u003e\n);\n\nexport const getStaticProps: GetStaticProps\u003cData\u003e = async (_ctx) =\u003e {\n  /* Using server-side SDK: */\n  const definitions = await getDefinitions();\n  const context = {}; // optional, see https://docs.getunleash.io/reference/unleash-context\n  const { toggles } = evaluateFlags(definitions, context);\n\n  /* Or with the proxy/front-end API */\n  // const { toggles } = await getFrontendFlags({ context });\n\n  const flags = flagsClient(toggles);\n\n  return {\n    props: {\n      isEnabled: flags.isEnabled(\"nextjs-example\"),\n      variant: flags.getVariant(\"nextjs-example\"),\n    },\n  };\n};\n\nexport default ExamplePage;\n```\n\nThe same approach will work for [ISR (Incremental Static Regeneration)](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration).\n\nBoth `getDefinitions()` and `getFrontendFlags()` can take arguments overriding URL, token and other request parameters.\n\n## E). Server Side Rendering (SSR)\n\n```tsx\nimport {\n  flagsClient,\n  evaluateFlags,\n  getDefinitions,\n  type IVariant,\n} from \"@unleash/nextjs\";\nimport type { GetServerSideProps, NextPage } from \"next\";\n\ntype Data = {\n  isEnabled: boolean;\n};\n\nconst ExamplePage: NextPage\u003cData\u003e = ({ isEnabled }) =\u003e (\n  \u003c\u003eFlag status: {isEnabled ? \"ENABLED\" : \"DISABLED\"}\u003c/\u003e\n);\n\nexport const getServerSideProps: GetServerSideProps\u003cData\u003e = async (ctx) =\u003e {\n  const sessionId =\n    ctx.req.cookies[\"unleash-session-id\"] ||\n    `${Math.floor(Math.random() * 1_000_000_000)}`;\n  ctx.res.setHeader(\"set-cookie\", `unleash-session-id=${sessionId}; path=/;`);\n\n  const context = {\n    sessionId, // needed for stickiness\n    // userId: \"123\" // etc\n  };\n\n  const definitions = await getDefinitions(); // Uses UNLEASH_SERVER_API_URL\n  const { toggles } = evaluateFlags(definitions, context);\n\n  const flags = flagsClient(toggles); // instantiates a static (non-syncing) unleash-proxy-client\n\n  return {\n    props: {\n      isEnabled: flags.isEnabled(\"nextjs-example\")\n    },\n  };\n};\n\nexport default ExamplePage;\n```\n\n## F). Bootstrapping / rehydration\n\nYou can bootstrap Unleash React SDK to have values loaded from the start.\nInitial value can be customized server-side.\n\n```tsx\nimport App, { AppContext, type AppProps } from \"next/app\";\nimport {\n  FlagProvider,\n  getFrontendFlags,\n  type IMutableContext,\n  type IToggle,\n} from \"@unleash/nextjs\";\n\ntype Data = {\n  toggles: IToggle[];\n  context: IMutableContext;\n};\n\nexport default function CustomApp({\n  Component,\n  pageProps,\n  toggles,\n  context,\n}: AppProps \u0026 Data) {\n  return (\n    \u003cFlagProvider\n      config={{\n        bootstrap: toggles,\n        context,\n      }}\n    \u003e\n      \u003cComponent {...pageProps} /\u003e\n    \u003c/FlagProvider\u003e\n  );\n}\n\nCustomApp.getInitialProps = async (ctx: AppContext) =\u003e {\n  const context = {\n    userId: \"123\",\n  };\n\n  const { toggles } = await getFrontendFlags(); // use Unleash Proxy\n\n  return {\n    ...(await App.getInitialProps(ctx)),\n    bootstrap: toggles,\n    context, // pass context along so client can refetch correct values\n  };\n};\n```\n\n# Server-side flags and metrics (new in v1.5.0)\n\nNext.js applications using Server-Side Rendering (SSR) are often deployed in serverless or short-lived environments, such as Vercel. This creates challenges for server-side metrics reporting.\n\nTypically, Unleash backend SDKs (like the [Node.js SDK](https://github.com/Unleash/unleash-client-node) run in long-lived processes, allowing them to cache metrics locally and send them to the Unleash API or Edge API at scheduled intervals.\n\nHowever, in some short-lived serverless environments where Next.js is commonly hosted (e.g., Vercel), there is no persistent in-memory cache across multiple requests. As a result, metrics must be reported on each request.\n\nTo address this, the SDK provides a `sendMetrics` function that can be called wherever needed, but it should be executed after feature flag checks `client.isEnabled()` or variant checks `client.getVariant()`.\n\nWe also recommend setting up the [Edge API](https://github.com/Unleash/unleash-edge)  in front of your Unleash API. This helps protect your Unleash API from excessive traffic caused by per-request metrics reporting.\n\n```tsx\nconst enabled = flags.isEnabled(\"nextjs-example\");\n\nawait flags.sendMetrics();\n```\n\n## No `setInterval` support (e.g. Vercel)\n\nIf your runtime does not allow `setInterval` calls then you can report metrics on each request as shown below. Consider using Unleash Edge in this scenario.\n\n### Next.js 15 and newer\n\nLatest versions of Next.js allow to run code after the response is sent, with [`after` function](https://nextjs.org/docs/app/api-reference/functions/after).\n\n```ts\nimport { after } from 'next/server'\n// ...\nexport default async function Page() {\n\n  // ...\n  const flags = flagsClient(evaluated.toggles)\n  const isEnabled = flags.isEnabled(\"example-flag\")\n\n  after(async () =\u003e {\n    flags.sendMetrics()\n  })\n\n  return (\n    // ...\n  )\n}\n```\n\n### Next.js 14 and older\n\n#### App router\n\n```tsx\nimport {evaluateFlags, flagsClient, getDefinitions,} from \"@unleash/nextjs\";\n\nexport default async function Page() {\n  const definitions = await getDefinitions({\n    fetchOptions: {\n      next: { revalidate: 15 }, // Cache layer like Unleash Proxy!\n    },\n  });\n  const context = {};\n  const { toggles } = evaluateFlags(definitions, context);\n  const flags = flagsClient(toggles);\n\n  const enabled = flags.isEnabled(\"nextjs-example\");\n\n  // await client.sendMetrics().catch(() =\u003e {}); // blocking metrics\n  flags.sendMetrics().catch(() =\u003e {}); // non-blocking metrics\n\n  return  \u003c\u003eFlag status: {enabled ? \"ENABLED\" : \"DISABLED\"}\u003c/\u003e\n}\n```\n\n#### Page router\n```tsx\nimport { evaluateFlags, flagsClient, getDefinitions } from \"@unleash/nextjs\";\nimport {GetServerSideProps, NextPage} from \"next\";\n\ntype Data = {\n  isEnabled: boolean;\n};\n\nexport const getServerSideProps: GetServerSideProps\u003cData\u003e = async () =\u003e {\n  const definitions = await getDefinitions({\n    fetchOptions: {\n      next: { revalidate: 15 }, // Cache layer like Unleash Proxy!\n    },\n  });\n  const context = {};\n  const { toggles } = evaluateFlags(definitions, context);\n  const flags = flagsClient(toggles);\n\n  const enabled = flags.isEnabled(\"nextjs-example\");\n\n  // await client.sendMetrics().catch(() =\u003e {}); // blocking metrics\n  flags.sendMetrics().catch(() =\u003e {}); // non-blocking metrics\n\n  return {\n    props: { isEnabled: enabled },\n  };\n};\n\nconst ExamplePage: NextPage\u003cData\u003e = ({ isEnabled }) =\u003e (\n  \u003c\u003eFlag status: {isEnabled ? \"ENABLED\" : \"DISABLED\"}\u003c/\u003e\n);\n\nexport default ExamplePage;\n```\n\n\n## Next.js middleware\n\nIn `middleware.ts` you can use [`event.waitUntil()`](https://nextjs.org/docs/app/building-your-application/routing/middleware#waituntil-and-nextfetchevent) to reliably send metrics without delaying the response.\n\n```tsx\nexport async function middleware(req: NextRequest, event: NextFetchEvent) {\n    // ...\n    const evaluated = evaluateFlags(definitions, context);\n    const flags = flagsClient(evaluated.toggles)\n    const isEnabled = flags.isEnabled(\"example-flag\")\n\n    event.waitUntil(flags.sendMetrics())\n    // ...\n}\n```\n\n## `setInterval` support (e.g. long-running Node process or AWS lambda)\n\nIf your Next application resolves flags only in SSR mode and `setInterval` is supported then you may also consider using [Node.js SDK](https://github.com/Unleash/unleash-client-node) instead, which is less taxing on metrics reporting.\nCheck [this blog post](https://docs.getunleash.io/feature-flag-tutorials/serverless/lambda) for more information on short-running lambdas that still support `setInterval`.\n\n\n# ⚗️ CLI (experimental)\n\nYou can use `unleash [action] [options]` in your `package.json` `scripts` section, or with:\n\n```sh\nnpx @unleash/nextjs\n```\n\nFor the CLI to work, the following [environment variables](#environment-variables) must be configured with appropriate values:\n\n- `UNLEASH_SERVER_API_URL`\n- `UNLEASH_SERVER_API_TOKEN`\n\nThe CLI will attempt to read environment values from any `.env` files if they're present. You can also set the variables directly when invoking the interface, as in the [CLI usage example](#example).\n\n## Usage\n\n- `get-definitions \u003coutputFile.json\u003e` Download feature flags definitions for bootstrapping (offline use) of server-side SDK.\n- `generate-types [options] \u003coutputFile.ts\u003e` Generate types and typed functions from feature flags defined in an Unleash instance.\n  It will also generate strictly typed versions of `useFlag`, `useVariant`, `useFlags` and `flagsClient` (unless `--typesOnly` is used).\n  - `-t, --typesOnly` don't include typed versions of functions exported from `@unleash/nextjs` (default: false)\n  - `-b, --bootstrap \u003csourceFile.json\u003e` load definitions from a file instead of fetching definitions - work offline\n- `-V` Output the version number\n\n## Example\n\nTry it now\n\n```sh\nUNLEASH_SERVER_API_URL=https://app.unleash-hosted.com/demo/api \\\nUNLEASH_SERVER_API_TOKEN=test-server:default.8a090f30679be7254af997864d66b86e44dcfc5291916adff72a0fb5 \\\nnpx @unleash/nextjs generate-types ./unleash.ts\n```\n\n# Known limitation\n\n- When used server-side, this SDK does not support the \"Hostname\" and \"IP\" strategies. Use custom context fields and constraints instead.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funleash%2Funleash-client-nextjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funleash%2Funleash-client-nextjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funleash%2Funleash-client-nextjs/lists"}