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

@splithub/next

v0.5.1

Published

SplitHub for Next.js: experiments and analytics with middleware, server components, redirect experiments and the route for your own database.

Readme

@splithub/next

SplitHub for Next.js (App Router, 14+). Three entry points:

| Import | Runs | What it gives you | |---|---|---| | @splithub/next | edge (middleware) | splithubMiddleware(config): visitor cookie, header for RSC, invisible rewrites for redirect experiments, edge exposures | | @splithub/next/server | Server Components, Route Handlers | getVisitorId(config), getSplitHub(config) → .variant(id), .value(id) | | @splithub/next/client | Client Components | SplitHubNextProvider, Experiment, Variant, useVariant, useValue, useTrack, Exposure |

Setup (what npx splithub init does)

// middleware.ts
import { splithubMiddleware } from '@splithub/next';
import config from './splithub.config';
export default splithubMiddleware(config);
export const config = { matcher: ['/((?!_next|api|.*\\..*).*)'] };
// app/api/splithub/[[...path]]/route.ts   (self-hosted mode)
import { createSplitHubHandler } from '@splithub/node';
import { sqliteStore } from '@splithub/adapter-sqlite';
import config from '../../../../splithub.config';
const handler = createSplitHubHandler({ config, store: sqliteStore(), adminToken: process.env.SPLITHUB_ADMIN_TOKEN });
export const POST = handler;
export const GET = handler;
export const runtime = 'nodejs';
// app/layout.tsx (Server Component)
import { SplitHubNextProvider } from '@splithub/next/client';
import { getSplitHub } from '@splithub/next/server';
import config from '../splithub.config';

export default async function RootLayout({ children }) {
  const sh = await getSplitHub(config);
  return (
    <html><body>
      <SplitHubNextProvider config={config} visitorId={sh.visitorId ?? undefined} remoteOverrides={sh.overrides}>
        {children}
      </SplitHubNextProvider>
    </body></html>
  );
}

Live overrides (cloud mode)

npx splithub pause <id> (or the dashboard) pauses an experiment, changes traffic/weights or swaps value payloads without a deploy. The middleware and getSplitHub fetch GET /v1/overrides/<pk>.json at most once per 60 s per isolate and apply it on top of the config file; the layout passes the same overrides to the client provider so hydration agrees. Opt out with splithubMiddleware(config, { remote: false }).

Using experiments

Client Components: same API as @splithub/react, imported from @splithub/next/client.

Server Components:

import { getSplitHub } from '@splithub/next/server';
import { Exposure } from '@splithub/next/client';

export default async function Page() {
  const sh = await getSplitHub(config);
  const title = sh.value<string>('hero-title');
  return (
    <>
      <h1>{title}</h1>
      <Exposure id="hero-title" />   {/* records the exposure once on the client */}
    </>
  );
}

Redirect experiments need no code: declare kind: 'redirect' with match and per-variant to, and the middleware rewrites the request. The URL in the address bar does not change and the visitor sees no flash.

Why no flicker

The middleware decides the visitor id before anything renders, Server Components compute the same deterministic assignment as the client, and the client provider receives that id as a prop. Both sides agree on the first byte.