knext

The official Next.js compatibility credential

Exactly what knext's compatibility credential covers, what it does not, and its current status — stated honestly, not as a marketing claim.

knext's goal is verified-adapter status: open source, validated against the official Next.js compatibility suite, honest about every exclusion. knext does not claim that status yet. This page states precisely what that credential covers today, what it explicitly does not cover, and the current status of the in-progress credentialing window — including while that window has not yet completed.

Status, stated plainly. The v1.0 credentialing window is in progress, not complete. A cell only counts as credentialed once it has banked 14 consecutive scheduled runs, each started at least two hours after the previous counted run and each with every shard reporting zero failed and zero not-run tests, run against one frozen release-candidate build. No cell has reached that bar yet. Treat every number on this page as current evidence for where a cell stands today — never as a finished, all-fourteen-runs-passing result. See the compatibility matrix for each cell's current status and the evidence behind it, which this page deliberately does not duplicate.

What "the official suite" is

There is no separate @next/compat-suite package. The official compatibility harness is a mode of Next.js's own end-to-end test suite: check out vercel/next.js, build it, and run its deploy-eligible e2e tests with NEXT_TEST_MODE=deploy, pointing the harness at an adapter's own lifecycle scripts. Each test builds a real Next.js app through the adapter and asserts over real HTTP against the deployment those scripts produce — the same validation path the reference adapters use.

The four cells the v1.0 credential covers

knext's v1.0 credential is a matrix, not a single number. Four combinations are in scope:

RuntimeBuilder
NodeTurbopack
Nodewebpack
BunTurbopack
Bunwebpack

Each cell is a standalone build (next build's output: 'standalone' server), booted on its own runtime. Turbopack on Bun is knext's default — the standalone server compiled into a bytecode executable — and each of the other three combinations is user-selectable. Every cell runs the identical test corpus and shard layout; the only variable that changes between cells is the runtime and the builder.

What this table does not include. The compiled vinext build (a separate, Vite-based implementation of Next.js) is measured against the same corpus, but it is not one of the four v1.0 cells — see what's out of scope below.

For the current evidence behind each of these four cells — run counts, pass/fail totals, and credential-run progress — see the compatibility matrix; this page is the scope-and-methodology reference, not the scoreboard.

The Next.js version under credential

The credential runs against a pinned Next.js release tag, never canary, so an upstream regression is never mistaken for a knext defect. As of the current credentialing round the pinned tag is the same Next.js release that knext create scaffolds today — there is no deliberate version gap between what is credentialed and what a new app ships with.

It runs against published release-candidate packages, not main

A single green run — even a green nightly on the fast-moving main branch — is evidence, not a credential. The v1.0 bar requires every credential run to execute against one frozen release-candidate build: a specific @getknext/* release-candidate tag, published to npm under the rc dist-tag, checked out at a fixed commit rather than re-resolved on each run. This keeps a 14-run streak from being reset by unrelated day-to-day changes on main while it is banking — and it means the credential is earned by the exact bytes an outside user installing @getknext/core@rc would get, not by a moving target.

Nightly runs on main keep running as an early-warning signal — a red one still raises an alarm — but they can never advance a cell toward its 14-run credential. Only a scheduled run against the pinned release-candidate build counts.

Each cell is scheduled three times a day, eight hours apart. Every run starts with fresh caches, and a manually dispatched run never counts. A run counts toward the 14 only if it started at least two hours after the previous counted run and ran the same frozen build; a red run resets the streak.

Stable releases and the credential

A stable release can ship while its credential is still in progress. When it does, its packages are cut from the release candidate under credential with only the version fields changed — every other byte of every published tarball is identical, and the release pipeline checks that before it publishes. So the runs banking against the release candidate describe exactly the code a stable install runs. The stable release is still not credentialed until every cell reaches its 14 consecutive runs; its release notes say so, and so does this page until then.

The 14-run window is currently open, not complete. A release-candidate build is pinned and the credential runs are executing against it. As of today, no cell has yet accumulated 14 consecutive qualifying runs against this build — the count is in progress. This page will be updated with each cell's credentialed status once a streak actually completes; until then, no claim on this page should be read as a completed fourteen-run streak.

The quarantine list — and why it exists

The credential is scoped against Next.js's own deploy-eligible test selection, minus three documented, auditable categories of subtraction. All three shrink toward zero over time and none is added pre-emptively — only from an observed, evidenced failure.

1 · Architectural exclusions

A small, fixed set of test categories is excluded because knext does not implement the capability they test, not because the tests fail unpredictably:

CategoryWhy it's excluded
Edge Runtimeknext runs a Node/Bun standalone server; it has no V8-isolate edge runtime.
Edge MiddlewareEdge Middleware requires the Edge Runtime; knext supports only the Node middleware convention.
Partial Prerendering (PPR)Not yet adapter-standardizable upstream.
Cache Components ('use cache')An evolving upstream API, not yet stabilized for adapters.

These are also documented on the compatibility matrix as explicit ⛔ rows — out of scope today, not silently skipped.

2 · Tests upstream itself already skips

Next.js's own deploy-tests manifest marks some cases as known-unreliable against its own reference deploy target. knext mirrors those upstream skips verbatim — running them anyway would book upstream's own noise as a knext failure, which is not an honest signal either way. This category is not knext-specific debt; it is carried over from upstream's own manifest.

3 · knext's own observed-failure quarantine ledger

A separate, smaller ledger quarantines individual test cases — or, in a bounded number of cases, whole files — that knext itself has observed failing for a documented, evidenced reason. Every entry records its observed failure mechanism and upstream provenance, and is checked mechanically so an entry cannot be added without that evidence; this ledger is re-reviewed whenever the credentialed Next.js version moves. It currently holds two distinct families:

  • bun-edge-fetch — a Bun-runtime edge-sandbox outbound fetch() gap: an edge-runtime fetch() call resolves but its response body never settles, hanging the test until it times out. This is a Bun runtime limitation, independent of the Next.js version under test.
  • vercel-infra-coupled — tests whose deploy-mode assertion encodes behavior that only Vercel's own hosting infrastructure produces (for example, a response header set by Vercel's own CDN), not anything a self-hosted deployment can or should reproduce. Older entries in this family were checked case-by-case against knext's result. Entries added at Next 16.4.3 were classified from the failing assertion and its deploy branch in the upstream test source; a self-hosted match was not re-run for them. These entries exclude a whole file, so they are used only for files where every case that runs fails.

Counts, kept honest by a CI check. As of the current manifest, bun-edge-fetch quarantines 2 entries (3 test cases) and vercel-infra-coupled quarantines 9 entries (36 test cases). These numbers are asserted against the manifest by a docs test, so this page cannot silently drift from the ledger it describes.

4 · Per-case entries pinned to one Next.js version

A file that fails only some of its cases should not lose the cases that pass. For a failure that is deterministic (it fails the same way every run, so it is not a flake) knext deselects the individual case, never the file, and only under bars that are each checked by CI:

  • Pinned to a version. The entry names the exact Next.js version it was measured at. Before the tests run, the harness drops the entry's deselections at any other version, so those cases run there, and a missing or unreadable version fails the step. CI also rejects an entry once no test lane runs its version, so bumping the credentialed version forces every entry to be re-measured or removed. A lane pinned to an older release candidate has no such entries to scope; a lane gains the step when its candidate is cut from a build that includes it.
  • Exact case names that must still exist. The entry lists full test names, and CI checks each against a snapshot of the upstream test file at that version. A separate job re-fetches the upstream files on every change to the list and nightly, and fails if the snapshot differs or upstream cannot be reached. A name that has disappeared upstream fails the check.
  • Cited and categorised. The entry cites the upstream file line it rests on and a mechanism category (a Vercel-only header, an upstream expected-failure marker, a harness gap, and so on), with a written reason.
  • Measured, per cell. The entry records the run IDs and which of the four cells (Node or Bun, Turbopack or webpack) it was measured on, and may not claim a cell nobody measured.
  • Capped. Files and cases are both counted, with a hard ceiling of 10 files and 20 cases.

A deselected case is not run, so one that starts passing is not reported until the version moves and the entry is re-measured. These checks establish form, not truth: that a citation is on the line it names, not that the failure is really what the entry says. Review of each entry is what guards that.

Counts, kept honest by a CI check. The per-case list currently holds 9 files (19 test cases), measured at Next.js 16.4.3 on the Node/Turbopack and Bun/webpack cells. The Node/webpack and Bun/Turbopack cells were not measured at that version and no entry claims them.

One entry is a known gap in Bun support, not a Vercel-specific behavior: the fixture's native addon uses the V8 C++ API, and the Bun runtime loads it with a different native-module ABI version than Node. Those 2 cases are deselected so the Bun cell is not red. This is not a claim that V8-API native addons work on Bun. Because one manifest serves every cell, the Node/Turbopack cell, which was measured passing, also stops running those 2 cases; the Node/webpack cell was not measured.

5 · A known defect in the Bun runtime, scoped to one cell

Some failures are caused by a bug in a runtime knext does not own, on one cell only. For these, knext keeps a separate, small list. An entry is admitted only when all of the following hold, each checked by CI:

  • One cell. The entry names exactly one runtime and one builder (for example, Bun with Turbopack). Before the tests run, the harness deselects the entry's cases on that cell only, and only at the Next.js version and the Bun version the entry was measured at. On every other cell, version or Bun build the cases run.
  • Whole files are excluded, not counted. When an entry covers every case in a test file, the harness skips the file on that cell rather than running it with no cases, so the run never counts that file as passed.
  • A named upstream fix. The entry cites the runtime's own issue and fix, and its removal condition is the release that contains that fix.
  • Cannot outlive the bug. Moving the Bun version the test lanes run fails CI until each entry is re-measured on the new Bun or removed. The entry must cite a run on the new Bun, so changing the recorded version without a run is not enough. The re-measure runs the cases, so a Bun release that fixes the bug shows them passing.
  • knext refuses the configuration. knext rejects the affected setup at build time, so an app cannot reach the failing state silently.
  • Exact names, measured, capped. Case names are checked against the upstream test file at that version, the entry records the runs it was measured on, and the list has its own ceiling of 5.

Counts, kept honest by a CI check. This list currently holds 2 files (2 test cases), both on the Bun/Turbopack cell at Next.js 16.4.3 on Bun 1.4.2. Both fixtures enable Next's experimental turbopackModuleFragments flag, which Turbopack compiles into code Bun's parser rejects when it loads it, where Node only fails if the code runs (it never does). The same files pass on the Node/Turbopack, Node/webpack and Bun/webpack cells, where they keep running. knext refuses turbopackModuleFragments on the Bun runtime; see Bun & the compiled executable.

No ledger above is used to manufacture a green run — they exist to keep the nightly signal honest, and they shrink toward zero over time rather than growing pre-emptively.

The harness boot-path caveat

The credential harness and the platform's real runtime boot a Next.js app somewhat differently depending on the runtime, and that difference is not swept under the numbers above.

  • Node cells. The harness boots the standalone server through knext's own shipped supervisor — the same wrapper process the operator runs in production, which handles graceful shutdown (draining in-flight requests and running after() callbacks on SIGTERM) and exposes a metrics endpoint. So the Node credential numbers are earned on close to the real production entrypoint. Two differences remain, both artifacts of running many deployments concurrently in CI rather than one in production: the metrics port is a dynamically chosen per-deploy port instead of the fixed production default, and the shutdown grace period is shorter than production's default so teardown fits inside the harness's own timeout.
  • Bun cells. The harness boots the compiled standalone executable directly — the compiled binary itself, not through a supervisor wrapper. The shipped production image's own Bun boot path does run through a supervisor-equivalent entrypoint; the harness's Bun cells do not exercise it, so their pass/fail numbers cover the compiled executable's own behavior, not that wrapper.

That gap is not left unverified, though: the supervisor-wrapped entrypoint's own behavior — that it applies the same compat-required response normalization, on both the Node- and Bun-standalone targets — is checked separately, by booting the actual shipped container image the way the operator boots it and asserting the normalized response over HTTP. So both boot paths are each verified, just by different checks, and a reader should not assume the harness numbers alone describe what production traffic actually boots on every cell.

What's out of scope

Three things are explicitly not covered by this credential, stated here so no reader has to infer it from an absence:

  • The compiled vinext executable. knext also offers a separate, Vite-based build of Next.js, compiled into a single Bun executable. It is measured against the same test corpus and the number is published, but it does not carry a 14-run credential window and is not one of the four v1.0 cells above — see Bun & the compiled executable for its own, separately-tracked status.
  • Edge Middleware and Partial Prerendering / Cache Components. Listed above as architectural exclusions — they are outside what the suite can even test against knext, because knext does not implement them, not because of a credentialing gap.
  • Cluster-level behavior. The suite validates one deployed app's HTTP behavior against a real Next.js corpus. It does not exercise Knative autoscaling, multi-tenant cluster behavior, the operator's reconciliation logic, or anything above the single-app HTTP surface — those are covered by knext's own operator and integration tests, not by this credential.

The per-PR smoke gate

Independently of the official suite, a fast in-repo smoke gate runs on every change: it builds an example app through the adapter, boots it on a Node + Bun matrix, and hard-asserts real HTTP behavior (App Router HTML, RSC flight payloads, route handlers, dynamic/static routes, middleware header injection). The official suite above is the correctness credential; the smoke gate is the minutes-fast regression tripwire in front of it.

For the per-feature status — each row backed by on-disk evidence and a CI guard test — see the compatibility matrix.

On this page