[!IMPORTANT]
This is an experimental project to demonstrate the use of LaunchDarkly with Next.js App Router.This is designed for the App Router. Pages router is not supported.
This solution uses the Node Server SDK and the Javascript SDK. It features:
/app/components/helloLDClient.tsx
/app/components/helloLDRSC.tsx
This is a Next.js project bootstrapped with create-next-app
using App Router.
To run this project:
LD_SDK_KEY='<YOUR LD SERVER SDK KEY>'
NEXT_PUBLIC_LD_CLIENT_SIDE_ID='<YOUR LD CLIENT SDK KEY>'
Optional -
dev-test-flag
in your LaunchDarkly environment or replace with your own flags in helloLDClient.tsx
and/or helloLDRSC.tsx
.yarn && yarn dev
or npm i && npm run dev
You should see your flag value rendered in the browser.
The code under ld
exposes server and client apis.
initNodeSdk
- Initializes the Node SDK on server startup using the instrumentation hook
getBootstrap
- Returns a json suitable for bootstrapping the js sdk.
useLDClientRsc
- Use this to get an ldClient for Server Components.
LDProvider
- The react context provider.
useLDClient
- Use this to get an ldClient for Client Components.
Follow these instructions if you want to test this apis in your own project:
next.config.mjs
:/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: { instrumentationHook: true },
};
export default nextConfig;
instrumentation.ts
at the root of your project. This will initialize the Node Server SDK.import { initNodeSdk } from '@/ld/server';
export async function register() {
await initNodeSdk();
}
LDProvider
using your LDContext
and bootstrap
:export default async function RootLayout({
children,
}: Readonly<{
children: ReactNode;
}>) {
// You must supply an LDContext. For example, here getLDContext
// inspects cookies and defaults to anonymous.
const context = getLDContext();
// A bootstrap is required to initialize LDProvider.
const bootstrap = await getBootstrap(context);
return (
<html lang="en">
<body className={inter.className}>
<LDProvider context={context} options={{ bootstrap }}>
{children}
</LDProvider>
</body>
</html>
);
}
useLDClientRsc
function, and can be async or non-async:// You should use your own getLDContext function.
import { getLDContext } from '@/app/utils';
import { useLDClientRsc } from '@/ld/server';
export default async function HelloRSC() {
const ldc = await useLDClientRsc(getLDContext());
const flagValue = ldc.variation('dev-test-flag');
return (
<div className="border-2 border-white/20 p-4">
<p className="text-xl ldgradient">
{flagValue
? "This flag is evaluating True in a React Server Component"
: "This flag is evaluating False in a React Server Component"}
</p>
</div>
);
}
useLDClient
hook:'use client';
import { useLDClient } from '@/ld/client';
export default function HelloClient() {
const ldc = useLDClient();
const flagValue = ldc.variation('dev-test-flag');
return (
<div className="border-2 border-white/20 p-4 ">
<p className="ldgradient text-xl">
{flagValue
? "This flag is evaluating True running Client-Side JavaScript"
: "This flag is evaluating False running Client-Side JavaScript"}
</p>
</div>
);
}
You will see both components are rendered on the server (view source on your browser). However, only Client Components will respond to live changes.