Next.js

next-precog is a route handler plus a provider, for the App Router.
App Router only. The Pages Router needs a different API route and a different prefetch call, and is not supported yet.

Install

npm i next-precog
.env
TYPESAFE_API_KEY="your-api-key"

Using a Vercel AI Gateway key? Name it AI_GATEWAY_API_KEY and the handler routes through the gateway on its own.

The route handler

The key stays on the server, which is the whole reason this route exists.

app/api/precog/route.ts
import { createPrecogHandler } from "next-precog/server";

export const POST = createPrecogHandler();

It validates the body itself, rate limits per caller, caches in process, and answers 503 with an empty prediction on any failure, with the reason in x-precog-reason.

The provider

app/layout.tsx
import { PrecogProvider, PrecogOverlay } from "next-precog";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <PrecogProvider>
          {children}
          {process.env.NODE_ENV === "development" ? <PrecogOverlay /> : null}
        </PrecogProvider>
      </body>
    </html>
  );
}

PrecogProvider takes the same options as the Nuxt module, as props:

<PrecogProvider
  mode="auto"
  endpoint="/api/precog"
  thresholds={{ prefetch: 0.25, prerender: 0.6 }}
/>

Hand it the prefetching

This is the step that makes a difference, and it has no equivalent config flag.

Next prefetches every <Link> that enters the viewport, so a page of thirty links fetches thirty RSC payloads and there is nothing left to narrow. There is no global switch, so swap the import:

import { PrecogLink as Link } from "next-precog";

PrecogLink is next/link with prefetch={false}, which leaves precog to choose and still lets Next prefetch on hover. Pass prefetch explicitly to opt one link back in.

Without this the overlay still works and speculation rules still apply, but the in-app win is gone: everything was already warm.

What it warms

router.prefetch() for the routes the model picked, which fetches the route's RSC payload and its chunks. The payload only exists for routes Next renders ahead of time, so a statically generated section gains the most and a fully dynamic one gains least.

Reading the state

"use client";
import { usePrecog } from "next-precog";

const { enabled, pause, resume, refresh, metrics, plan } = usePrecog();

Not there yet

  • No DevTools panel. The Nuxt adapter has one; React DevTools has no equivalent hook for it.
  • No published benchmark. The numbers were measured on the Nuxt playground, and the two effectors are the same, but nobody has run the harness against Next. Do not assume they transfer exactly.