npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@variantlab/next

v0.1.10

Published

Next.js 14 and 15 bindings for variantlab — App Router, Pages Router, and Edge runtime.

Readme

@variantlab/next

Next.js 14 and 15 bindings for variantlab — App Router, Pages Router, and Edge runtime.

npm version

What this package gives you

  • SSR-correct variant resolution. Resolve variants on the server, seed them into the client engine, and render the same tree twice — no hydration mismatches.
  • Sticky cookies. A base64url-encoded __variantlab_sticky cookie persists the userId (and, optionally, pre-resolved assignments) across requests so every refresh shows the same variants.
  • Edge-runtime compatible. No Node-only APIs, no process.env, no cookie package, no crypto.createHash. Runs on Vercel Edge, Cloudflare Workers, and Deno Deploy.
  • Four subpath entrypoints. Server-only helpers (.), Client Component provider + hooks (/client), and router-scoped convenience helpers (/app-router, /pages-router).
  • ≤ 2 KB gzipped for the server entrypoint, ≤ 1 KB gzipped for /client.

Peer dependencies

  • next ^14.0.0 || ^15.0.0
  • react ^18.2.0 || ^19.0.0

Quick start — App Router

// middleware.ts
import { NextResponse } from "next/server";
import { variantLabMiddleware } from "@variantlab/next";
import experiments from "./experiments.json";

export const runtime = "edge";
export const config = { matcher: ["/((?!_next|.*\\..*).*)"] };

const apply = variantLabMiddleware(experiments);

export default function middleware(req) {
  return apply(req, NextResponse.next());
}
// app/layout.tsx (Server Component)
import { cookies } from "next/headers";
import { createVariantLabServer } from "@variantlab/next";
import { VariantLabProvider } from "@variantlab/next/client";
import experiments from "./experiments.json";

const server = createVariantLabServer(experiments);

export default function RootLayout({ children }) {
  const props = server.toProviderProps(cookies());
  return (
    <html lang="en">
      <body>
        <VariantLabProvider config={experiments} {...props}>
          {children}
        </VariantLabProvider>
      </body>
    </html>
  );
}
// app/page.tsx (Server Component)
import { cookies } from "next/headers";
import { getVariantValueSSR } from "@variantlab/next";
import experiments from "./experiments.json";

export default function Page() {
  const hero = getVariantValueSSR<string>("hero-copy", cookies(), experiments);
  return <h1>{hero}</h1>;
}
// app/client-demo/page.tsx
"use client";
import { useVariantValue, Variant } from "@variantlab/next/client";

export default function ClientDemo() {
  const cta = useVariantValue<string>("cta-color");
  return (
    <main>
      <button style={{ background: cta }}>Go</button>
      <Variant experimentId="layout">
        {{
          compact: <p>compact</p>,
          expanded: <p>expanded</p>,
        }}
      </Variant>
    </main>
  );
}

Debug overlay

A side-panel overlay for viewing and overriding experiments during development. Includes the "use client" directive so it works in App Router without extra wrappers.

// app/layout.tsx
import { VariantDebugOverlay } from "@variantlab/next/debug";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <VariantLabProvider config={experiments} {...props}>
          {children}
          {process.env.NODE_ENV === "development" && <VariantDebugOverlay />}
        </VariantLabProvider>
      </body>
    </html>
  );
}

The overlay is tree-shakeable — it only ships when you import @variantlab/next/debug. See the @variantlab/react README for full customization options (position, theme, programmatic open/close).

Subpath exports

| Subpath | Contents | "use client" | |---|---|---| | @variantlab/next | Server helpers, middleware factory, cookie helpers, shared types | ❌ | | @variantlab/next/client | VariantLabProvider, all React hooks + components | ✅ | | @variantlab/next/debug | VariantDebugOverlay + imperative open/close | ✅ | | @variantlab/next/app-router | App Router-scoped re-exports + readPayloadFromCookies() | ❌ | | @variantlab/next/pages-router | Pages Router-scoped re-exports + readPayloadFromReq(req) | ❌ |

Notes on the spec

  • getVariantSSR / getVariantValueSSR are synchronous, matching the canonical contract in API.md. The underlying engine is synchronous, so an async wrapper would only add Promise allocation. If you're on Next 15 where cookies() is async, await it at the call site and pass the resolved store to getVariantSSR.
  • The middleware writes only { v, u, a: {} } on first visit — it does not compute assignments at the edge. Server Components / Route Handlers can use server.writePayload(...) to persist computed assignments back into the cookie if they want to avoid a re-evaluation on the next request.

See the root README for project overview, motivation, and roadmap.