{"id":39029008,"url":"https://github.com/tanben/sample-nextjs","last_synced_at":"2026-01-17T17:36:02.724Z","repository":{"id":181443280,"uuid":"653175979","full_name":"tanben/sample-nextjs","owner":"tanben","description":"This project showcases a robust integration of LaunchDarkly feature flags within a Next.js application, leveraging the App Router architecture. It demonstrates best practices for implementing LaunchDarkly in both Client and Server components, while exploring various rendering strategies to optimize performance and user experience.","archived":false,"fork":false,"pushed_at":"2025-08-27T22:46:48.000Z","size":6218,"stargazers_count":22,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-28T00:14:06.501Z","etag":null,"topics":["app-router","launchdarkly","nextjs","nextjs13","reactjs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tanben.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-06-13T14:41:17.000Z","updated_at":"2025-08-27T22:46:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"ff5cd6de-9c8c-4084-ae8e-9769f069835c","html_url":"https://github.com/tanben/sample-nextjs","commit_stats":null,"previous_names":["tanben/sample-nextjs"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tanben/sample-nextjs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanben%2Fsample-nextjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanben%2Fsample-nextjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanben%2Fsample-nextjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanben%2Fsample-nextjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tanben","download_url":"https://codeload.github.com/tanben/sample-nextjs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tanben%2Fsample-nextjs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28513512,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T13:38:16.342Z","status":"ssl_error","status_checked_at":"2026-01-17T13:37:44.060Z","response_time":85,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["app-router","launchdarkly","nextjs","nextjs13","reactjs"],"created_at":"2026-01-17T17:36:02.066Z","updated_at":"2026-01-17T17:36:02.708Z","avatar_url":"https://github.com/tanben.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LaunchDarkly Next.js App Router Demo\n\nThis is a sample LaunchDarkly implementation on Next.js using the App Router with Client and Server components and various rendering strategies. It demonstrates how to integrate LaunchDarkly feature flags into a Next.js application.\n\n\n\n![](img/overview.gif)*Rendering Performance: Server vs Client components*\n\n\n##  Integrating LaunchDarkly React SDK in Next.js\n### Challenges and Solutions (Updated for Next.js 15 \u0026 React 19)\n\n\nIf you're developing with client components in Next.js, it's crucial to have a good grasp of how the platform manages client-side prerendering and the impact it may have on browser-specific libraries such as the LaunchDarkly React web SDK. For more information on this topic, I suggest checking out this article titled [\"Why do Client Components get SSR'd to HTML?\"](https://github.com/reactwg/server-components/discussions/4).\n\n\nNext.js improves page load times by prerendering **both Client and Server components** on the server and sending prerendered HTML to the browser.  This makes page load times faster, especially for pages with lots of content and complex JavaScript.\n During server-side prerendering, Client components do not involve hydration, which can cause runtime errors when browser-specific APIs are used such as when calling LaunchDarkly React SDK `asyncWithLDProvider`.\n\n**Important Changes in Next.js 15 \u0026 React 19:**\n- The `use()` hook now requires **stable/cached promises** and cannot be used with promises created during render. \n- Server Components cannot use `ssr: false` with `next/dynamic`. Read [Invalid Usage of `suspense` Option of `next/dynamic`](https://nextjs.org/docs/messages/invalid-dynamic-suspense) for details.\n- New error: \"A component was suspended by an uncached promise\"\n\nTo avoid these issues, consider implementing the following **updated approach**:\n\n1. Initialize the LaunchDarkly React SDK in a Client component using traditional async patterns.\n2. Use code-splitting to defer the loading of the React web SDK until page hydration phase.\n3. **Avoid using `use()` hook with promises created in render** - use `useEffect` and `useState` instead for compatibility. Read  [React v19 use() does not support promises created in render](https://react.dev/blog/2024/12/05/react-19#use-does-not-support-promises-created-in-render) for details.\n4. When using `dynamic()` with `ssr: false`, ensure the component calling it is a **Client Component** (has `\"use client\"` directive).  Read [Skipping SSR](https://nextjs.org/docs/app/guides/lazy-loading#skipping-ssr) for details.\n\nHere is an example of how to incorporate these modifications:\n\n Client component: `components/AsyncWithLDProvider.js`\n```\n\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { asyncWithLDProvider, basicLogger } from \"launchdarkly-react-client-sdk\";\n\nconst defaultContext = {\n  kind: \"user\",\n  key: \"user-key-123abc\",\n  name: \"Sandy Smith\",\n};\n\nconst createLDConfig = (clientSideID, context) =\u003e ({\n  clientSideID,\n  context,\n  timeout: 5,\n  options: {\n    logger: basicLogger({\n      destination: (line) =\u003e console.log(line),\n      level: \"debug\",\n    }),\n  },\n  reactOptions: {\n    useCamelCaseFlagKeys: true,\n  },\n});\n\nexport default function AsyncLDProvider({\n  children,\n  context = defaultContext,\n  clientSideID,\n}) {\n  const [LDProvider, setLDProvider] = useState(null);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState(null);\n\n  useEffect(() =\u003e {\n    if (!clientSideID) {\n      setError(new Error(\"clientSideID is required\"));\n      setLoading(false);\n      return;\n    }\n\n    let mounted = true;\n\n    const initializeLDProvider = async () =\u003e {\n      try {\n        const config = createLDConfig(clientSideID, context);\n        const provider = await asyncWithLDProvider(config);\n        \n        if (mounted) {\n          setLDProvider(() =\u003e provider);\n          setLoading(false);\n        }\n      } catch (err) {\n        if (mounted) {\n          setError(err);\n          setLoading(false);\n        }\n      }\n    };\n\n    initializeLDProvider();\n\n    return () =\u003e {\n      mounted = false;\n    };\n  }, [clientSideID, context]);\n\n  if (error) {\n    return \u003cdiv\u003eError: {error.message}\u003c/div\u003e;\n  }\n\n  if (loading || !LDProvider) {\n    return \u003cdiv\u003eLoading LaunchDarkly...\u003c/div\u003e;\n  }\n\n  return \u003cLDProvider\u003e{children}\u003c/LDProvider\u003e;\n}\n```\n\ncreate a client wrapper component : `components/ClientAsyncLDProvider.js`:\n```\n\"use client\";\n\nimport dynamic from \"next/dynamic\";\n\nconst LDAsyncPovider = dynamic(\n  () =\u003e import(\"@/components/AsyncWithLDProvider\"),\n  {\n    ssr: false,\n    loading: () =\u003e \u003cdiv\u003eLoading LaunchDarkly...\u003c/div\u003e\n  }\n);\n\nexport default function ClientAsyncLDProvider({ children, clientSideID }) {\n  return (\n    \u003cLDAsyncPovider clientSideID={clientSideID}\u003e\n      {children}\n    \u003c/LDAsyncPovider\u003e\n  );\n}\n```\n\nThen use it in `app/layout.js` (Server Component):\n```\nimport ClientAsyncLDProvider from \"@/components/ClientAsyncLDProvider\";\n\nexport default function Layout({ children }) {\n  return (\n    \u003cClientAsyncLDProvider clientSideID={process.env.CLIENT_SIDE_ID}\u003e\n      {children}\n    \u003c/ClientAsyncLDProvider\u003e\n  );\n}\n\n```\n\n\n\n## Prerequisites\n- LaunchDarkly account\n- LaunchDarkly React Web client SDK \u003e= 3.8.x\n- LaunchDarkly Node.js server SDK \u003e= 9.10.x\n- Node.js version \u003e= 18.17.x\n- Next.js version 15.x\n- React version 19.x\n  \n\u003eThis [Next.js](https://nextjs.org/) project was bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).\n\n\n\n## Setup\n1. Create a feature flag in your LaunchDarkly account with the following details:\n\n   | Flag Key      | Flag Type | Description         |\n   | ------------- | --------- | ------------------- |\n   | simple-toggle | boolean   | Toggles flag status |\n\n2. Clone this repository and navigate to the project directory.\n3. Install the required packages by running:\n\n    ```\n    npm install\n    ```\n4. Create a `.env` file in the project root and add the following environment variables:\n    ```\n    LAUNCHDARKLY_SDK_KEY=\"\u003cLaunchDarkly Server-side SDK Key\"\n    CLIENT_SIDE_ID=\"\u003cLaunchDarkly Client Side ID\u003e\"\n    ```\n    Replace `\u003cLaunchDarkly Server-side SDK Key\u003e` with your LaunchDarkly server-side SDK key and `\u003cLaunchDarkly Client-side ID\u003e` with your LaunchDarkly client-side ID.\n\n## Running the Demo\n\n1. Start the development server:\n\n    ```\n    npm run dev\n    ```\n    \u003e Note: If you encounter a Server 500 error while running the app, as discussed in [vercel/next.js#49677](https://github.com/vercel/next.js/issues/49677), switch to Node.js version 16.8.\n2. Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\n\n## Learn More\n\nFor more information check out the following resources:\n- [LaunchDarkly React Web SDK](https://docs.launchdarkly.com/sdk/client-side/react/react-web) - how to get started with the client-side React Web SDK, and links to reference information on all of the supported features.\n- [LaunchDarkly Quick Start Guide](https://docs.launchdarkly.com/home/getting-started) - describes how to get started with LaunchDarkly\n- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.\n- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.\n  \n\n\n\n\n## Deploy on Vercel\n\nThe easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template\u0026filter=next.js\u0026utm_source=create-next-app\u0026utm_campaign=create-next-app-readme) from the creators of Next.js.\n\nCheck out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftanben%2Fsample-nextjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftanben%2Fsample-nextjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftanben%2Fsample-nextjs/lists"}