Next.js SDK

Next.js feature flags that work on both sides

Evaluate a flag in a Server Component, in middleware at the edge, or in a client component, and get the same decision for the same user. No hydration mismatch, no flash of the wrong variant.

No card required

01 · Drop it in

The planned Next.js API, exactly as it will ship

The SDK is part of the early-access program, and this is its real surface: one install, one client, one call per decision. Every toggle, rollout step and kill-switch flip you make in the console reaches this code in about 3 seconds, with no redeploy.

Works with the App Router and the Pages Router; flag reads add roughly a millisecond from the local cache.

npm install @toggled/nextjs
next.js · checkout.new-flow live
// app/checkout/page.tsx (Server Component)
import { getFlag } from '@toggled/nextjs/server';

export default async function CheckoutPage() {
  const newFlow = await getFlag('checkout.new-flow', {
    fallback: false,
    user: await currentUser(),
  });

  return newFlow ? <NewCheckout /> : <ClassicCheckout />;
}

02 · Built for Next.js

What Next.js feature flags get you

Server Components first

getFlag runs during server rendering, so the correct variant is in the HTML you stream. Nothing flickers when the page hydrates.

Middleware and edge ready

Evaluate flags in middleware to rewrite routes for a canary cohort, run an A/B test on a landing page, or gate a whole route group by plan.

One decision on both sides

The server decision is handed to the client SDK during hydration, so a client component reading the same key never disagrees with the server.

03 · Then the usual lifecycle

Flag it, target it, roll it out, measure, kill

Once checkout.new-flow exists in your Next.js code, everything else happens in the console: target the internal team, run a gradual rollout from 1% to 100%, read the impact with built-in A/B testing, and keep the kill switch under your thumb. The full walkthrough is on how Toggled works.

Flat pricing applies here too: unlimited seats and unlimited flags on every plan, so the whole Next.js team gets an account. Numbers are on the pricing page.

Same flags, other stacks

Cohorts agree across SDKs: a user in the 10% on your Next.js side is in the same 10% everywhere else.

Java, Rails, iOS and Android SDKs share the same core and ship with early access.

04 · Where the check goes

Where a flag check belongs in a Next.js codebase

01

Middleware for route-level splits

If the flag decides which route the user lands on, decide it in middleware and rewrite. A canary cohort goes to a different route group, an A/B test splits at the edge, and the pages themselves stay ordinary pages with no flag logic inside them.

02

Server Components for page-level variants

When both variants live on the same route, read the flag once at the top of the Server Component and pass the boolean into the tree. Children take a prop, which keeps them renderable in isolation, and the decision is already in the streamed HTML.

03

Client components only for post-load toggles

Reserve the client hook for things that change after the page is interactive: a panel that opens, a control that appears once the user acts. Anything visible in the first paint should be decided on the server, otherwise you have signed up for a flicker you cannot design around.

05 · Gotchas

Three ways Next.js feature flags go wrong

Gotcha 01

Two evaluations, two different user contexts

The Server Component evaluates with the session user; the client SDK boots with whatever it can see, which is often nothing yet. React then hydrates a different branch than it rendered and logs a mismatch. Bootstrap the client provider with the server decision so the client never re-decides on its own.

Gotcha 02

A flag read that quietly makes the route dynamic

Reading a per-user flag inside a Server Component opts that route out of static rendering, and the page you believed was cached at the edge is now rendered per request. If the flag only touches one widget on an otherwise static page, push the read into a small client island and keep the route cacheable.

Gotcha 03

Middleware that hits the network on every request

Middleware runs for every matching request, and a loose matcher means assets too. If the flag read there is a fetch rather than an in-memory evaluation, you have put a round trip at the front of every page load. Tighten the matcher, and only evaluate with an SDK that works locally in the edge runtime.

06 · Testing

Testing both paths in Next.js

Test the two sides separately, because they fail differently. For a Server Component, call the exported page function with a stubbed flag reader and assert on the markup it returns, or drive a route test with a forced override and check the HTML that comes back. For middleware, build a NextRequest per cohort and assert on the rewrite target instead of the rendered page.

next.js · test both paths
// middleware.test.ts (Vitest)
import { NextRequest } from 'next/server';
import { middleware } from './middleware';

vi.mock('@toggled/nextjs/server', () => ({
  getFlag: vi.fn(async () => true),
}));

test('the canary cohort is rewritten to the new checkout', async () => {
  const req = new NextRequest('https://app.test/checkout');
  const res = await middleware(req);

  expect(res.headers.get('x-middleware-rewrite')).toContain('/checkout-v2');
});

07 · People also ask

Next.js feature flag questions, answered

How do you use feature flags in Next.js Server Components?

Call an async flag read inside the component, await getFlag('checkout.new-flow', { user }), and branch before you return JSX. The decision is then baked into the HTML you stream, so nothing changes at hydration. Server Components cannot use hooks, so this has to be a plain async call rather than useFlag.

Why do feature flags cause a hydration mismatch in Next.js?

Because the server and the client evaluated the same key with different inputs. The server had the signed-in user; the client booted anonymous, before the SDK loaded, and React rendered the other branch on rehydrate. Pass the server decision into the client SDK as bootstrap state so both sides start from one value.

Can you evaluate feature flags in Next.js middleware?

Yes, and it is the right place for route-level decisions: rewriting a canary cohort into a different route group, splitting traffic for an A/B test, or blocking a route by plan. Middleware runs at the edge before rendering, so the evaluation has to be local and in memory, never a call to a flag API.

Do feature flags break Next.js caching or static rendering?

They can. A page that reads a per-user flag is dynamic by definition and cannot be one cached artifact for everyone. Keep the read out of statically rendered routes, or evaluate in middleware and vary the rewrite, or scope the branch to a small client component so the rest of the page stays static.

More answers, about the product rather than the code, live on the FAQ.

Early access · launching soon

Put your first Next.js feature behind a flag

Join the early-access list and be first in line when spots open. Flat pricing, unlimited seats, no card required.

No card required · your data stays yours