Skip to content
Shoal
Shoal

Guides

Next.js

Evaluate flags in server components, route handlers, middleware and the browser.

@shoal/next wraps the core SDK with helpers for the App Router. Flags are evaluated on the server, so pages render the right variation on the first byte — no flicker.

Terminal
npm install @shoal/next
Terminal
pnpm add @shoal/next
Terminal
yarn add @shoal/next
Terminal
bun add @shoal/next

Create a client

Create one client per process and reuse it. The helper caches the ruleset between requests.

lib/shoal.ts
import { createNextClient } from "@shoal/next";

export const shoal = createNextClient({
  key: process.env.SHOAL_KEY!,
  context: async ({ cookies }) => ({
    user: { id: cookies.get("uid")?.value ?? "anonymous" },
  }),
});

Server components

app/checkout/page.tsx
import { shoal } from "@/lib/shoal";

export default async function CheckoutPage() {
  const variant = await shoal.variation("checkout-theme", "classic");
  return variant === "compact" ? <CompactCheckout /> : <ClassicCheckout />;
}

Middleware

Rewrite to a different page at the edge — useful for full-page experiments.

middleware.ts
import { NextResponse, type NextRequest } from "next/server";
import { shoal } from "@/lib/shoal";

export async function middleware(req: NextRequest) {
  if (await shoal.isOn("new-pricing", { request: req })) {
    return NextResponse.rewrite(new URL("/pricing-v2", req.url));
  }
}

export const config = { matcher: "/pricing" };

Client components

Pass server-evaluated values down instead of evaluating in the browser:

app/layout.tsx
const flags = await shoal.bootstrap(["summer-banner", "chat-widget"]);
return <FlagsProvider value={flags}>{children}</FlagsProvider>;
components/banner.tsx
"use client";
import { useFlag } from "@shoal/react";
export function Banner() {
  return useFlag("summer-banner") ? <SummerBanner /> : null;
}
Edit this pageLast updated:
Was this page helpful?

Type to search. Results come from a local index — nothing leaves your browser.

↑ ↓ to navigate↵ to openMiniSearch · local