Tim Neutkens
90d · built 2026-08-09
90-day totals
- Commits
- 69
- Grow
- 7.7
- Maintenance
- 5.1
- Fixes
- 3.1
- Total ETV
- 15.8
30-day trajectory
Last 30 days vs. the 30 days before. Up arrows on Growth and ETV mean improvement; up arrow on Fixes share means more time on fixes (worse).
↑+337.5 %
vs 8 prior
↑+25.5 pp
recent vs prior
↑+2.8 pp
recent vs prior
Daily performance
Daily ETV, stacked by Growth, Maintenance and Fixes.
Work-mix over time
Share of Growth / Maintenance / Fixes over a rolling 7-day window. Reads as 'where is effort flowing right now'.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 20 by ETV in the 90-day window.
- 1.4ETVrequest insights: add DevTools request panel (5/5) (#93978) ## What? Adds the experimental Request Insights panel to the Next.js DevTools overlay. The panel provides: - A retained request list with stable selection as new requests arrive. - A “Page load” marker for the exact initial document request. - An end-to-end trace timeline that follows the recorded span hierarchy. - A focused default view of high-level spans and a verbose view for deeper investigation. - Fetch, cache, request, status, duration, and span-count details. - Readable sub-millisecond durations and consistent right-aligned request metrics. This PR is intentionally limited to the Request Insights UI. Additional OpenTelemetry coverage, span display names, and Server Action tracing are split into the dependent PRs below. ## Why? The Request Insights data was already available to tools, but inspecting it required consuming the development endpoint or CLI output. The DevTools panel makes the same request, fetch, cache, and timing information directly inspectable while developing an application. The focused/verbose split keeps the default trace useful for understanding the request lifecycle without hiding the lower-level spans needed for investigation. ## How? - Adds a Request Insights panel and request list to the DevTools overlay. - Builds timeline rows from recorded parent/child relationships instead of assigning synthetic sections. - Uses the request’s full duration as the timeline range and clips outlier spans to that range. - Merges recorded fetch metrics with their corresponding fetch spans. - Preserves the selected request ID until that request is no longer retained. - Compares `request.requestId` with `self.__next_r` to identify only the initial document request. ## Stack The first four Request Insights foundation PRs have already merged. The remaining review stack is: 1. **#93978 — Request Insights UI (this PR)** 2. #95765 — Missing OpenTelemetry spans 3. #95766 — Human-readable OpenTelemetry span names 4. #95767 — Server Action tracing and resolution ## Verification - `pnpm --filter=next build` - `pnpm exec jest packages/next/src/next-devtools/dev-overlay/components/request-insights/trace-viewer.test.ts --runInBand` <!-- NEXT_JS_LLM --> --------- Co-authored-by: Tim Neutkens <tim@timneutkens.nl>github.com-vercel-next.js · c427adf4 · 2026-07-14
- 1.3ETVrequest insights: record local framework spans (1/5) (#93974) ## What Adds a dev-only local recorder for framework OTEL spans. This lets Next mirror span data into an in-memory store when local span capture is enabled, without requiring a user to run an OTEL provider. Stack: 1. request insights: record local framework spans (1/5) ← current 2. request insights: derive request history and fetch data (2/5) 3. request insights: expose dev snapshots to tools and HMR (3/5) 4. request insights: add agent diagnosis access (4/5) 5. request insights: add DevTools request panel (5/5) ## Review Focus - Local recorder behavior when no OTEL provider is installed. - Preserving existing OTEL span API behavior when a provider is installed. - Request identity propagation through existing app render async storage. ## Proof In This PR - `pnpm jest packages/next/src/server/lib/trace/tracer.test.ts packages/next/src/server/lib/trace/span-store.test.ts --runInBand` - `pnpm --filter=next types` ## Deferred Coverage - Request-level aggregation, fetch enrichment, dev transport, CLI/MCP access, and the DevTools panel are later PRs in this stack. <!-- NEXT_JS_LLM_PR --> --------- Co-authored-by: Tim Neutkens <tim@timneutkens.nl>github.com-vercel-next.js · fab0afcb · 2026-07-12
- 1.1ETVFix Request Insights span collection (#95818) ## Summary Fix Request Insights collection so the dev server records all non-hidden Next.js spans locally, including non-vanilla trace and wrapped spans, while preserving the existing OpenTelemetry export allowlist unless verbose tracing is enabled. Keep reporting timelines correct by propagating request identity before work async storage exists, honoring explicit span timestamps, and anchoring request duration to the BaseServer request span. Standardize span categories on `next.span_category`, retain presentation-only UI filtering, and filter internal request identity headers at ingress. ## Verification - `pnpm test-dev-turbo test/development/app-dir/request-insights/request-insights.test.ts` <!-- NEXT_JS_LLM -->github.com-vercel-next.js · 491f7809 · 2026-07-16
- 1.0ETVRun Cache Components dev validation on a worker thread (#96153) This moves the dev-mode Cache Components validation renders off the dev server's main thread onto a worker thread, so rapid navigation no longer starves the event loop. The worker crosses into the app-page bundle exactly once, calling a new `ComponentMod.routeModule.runValidationInDev` entry that rebuilds the render context, work store, and request store from a serializable snapshot and runs the whole validation there, so the client prerender and the user's client components resolve the single app-page React instance rather than a second copy. A thin worker shell (`dev-validation-worker.ts`) plus a single-worker pool (`dev-validation-worker-pool.ts`) load the user bundle via `loadComponents`, install code-frame support for CLI output, and forward the validation errors back as Flight bytes; the main thread only delivers them to the overlay through `sendErrorsToBrowser`. The snapshot, the globalThis-symbol handoff, and the shared error-delivery helpers live in their own modules. The dev server installs the worker when `experimental.devValidationWorker` is not `false`, and `runDevValidationInBackground` uses it when present, falling back to the in-process path otherwise. A one-slot `SharedArrayBuffer` propagates a supersede abort into the worker so a newer navigation cancels an in-flight validation. The runtime bundle gains an `app-worker` entry for the worker with the `build/swc` boundary externalized for the code-frame native binding, and `patch-error-inspect.ts` now backs its code-frame renderer with a globalThis symbol so all copies of the module share it across the thread. The synthetic `bench/dev-validation` benchmark navigates back-to-back, so every click lands inside the validation window — the worst case for main-thread contention. Browser-observed navigation TTFB in that window, worker vs in-process: | Route | Worker (p50/p95/max) | In-process (p50/p95/max) | | ------ | -------------------- | ------------------------ | | client | 19 / 24 / 27 ms | 40 / 66 / 7762 ms | | server | 42 / 45 / 46 ms | 122 / 158 / 252 ms | | sprite | 109 / 117 / 169 ms | 196 / 208 / 299 ms | The steady-state difference is only tens of milliseconds; the effect that matters is the tail. In-process, a navigation that collides with an in-flight validation render can stall for seconds (this run peaked at ~7.8s on the client route, and the peak varies run to run) because a staged render does not yield until it finishes; off-thread the main thread stays free and that stall disappears. Read these as an upper bound, not a speedup that generalizes. The work moved off-thread is the validation render's CPU — bounded, route-dependent, and free of IO — so it does not grow with the main render's cost. In an app whose main render is dominated by IO the same absolute saving is a small fraction of the request, and it only appears when a navigation lands in the brief validation window; at ordinary click speed it is largely invisible. This is a dev-only responsiveness improvement whose benefit varies widely with the app and the navigation pattern. As a follow-up, the validation work that still runs on the main thread could move to the worker as well. When the main render can't be reused for validation (for example after a cache miss), the validation re-renders on the main thread to produce its inputs, resuming from the Resume Data Cache (RDC) the main render already filled, and only then hands the resulting Flight chunks to the worker. A later iteration could run those renders inside the worker too, transporting the (serializable) RDC so the worker can resume from the filled caches rather than reading them back on the main thread. closes NAR-895github.com-vercel-next.js · 3c4afc1a · 2026-07-25
- 0.7ETV(TypeScript 7 Support) Add experimental TypeScript CLI backend (#95639) ## Summary - add `experimental.useTypeScriptCli` so projects can explicitly run their local `tsc` during `next build`, including TypeScript 7 while the legacy JavaScript API is unavailable - preserve the TypeScript API backend as the default, with TypeScript 6-compatible dependency installation and actionable TypeScript 7 migration guidance - load effective compiler metadata through `tsc --showConfig`, preserve inherited path origins, stream native diagnostics, redirect incremental state, and forward worker termination to the compiler process tree - document the experimental behavior and cover TypeScript 6/7, both bundlers, raw diagnostics, full-project checking, dependency selection, and cleanup ## Demo ``` pnpm build > cna@0.1.0 build /Users/timneutkens/projects/sandbox/cna > next build ▲ Next.js 16.3.0-canary.81 (Turbopack) ✓ Running next.config.ts took 23ms - Cache Components enabled - Experiments (use with caution): ✓ useTypeScriptCli Creating an optimized production build ... ✓ Compiled successfully in 3.9s Running TypeScript ... app/page.tsx:8:3 - error TS2322: Type 'string' is not assignable to type 'number'. 8 return count++ + "abc"; ~~~~~~ Found 1 error in app/page.tsx:8 Failed to type check. Next.js build worker exited with code: 1 and signal: null ELIFECYCLE Command failed with exit code 1. ``` ## Verification - `pnpm test-start-turbo test/production/app-dir/typescript-cli/typescript-cli.test.ts` - `pnpm test-start-webpack test/production/app-dir/typescript-cli/typescript-cli.test.ts` - `pnpm test-start-turbo test/production/ci-missing-typescript-deps/index.test.ts` - `pnpm test-dev-turbo test/development/typescript-native-preview/index.test.ts` - `pnpm test-start-turbo test/production/typescript-basic/index.test.ts` <!-- NEXT_JS_LLM_PR -->github.com-vercel-next.js · a249dcbc · 2026-07-10
- 0.6ETVConvert more tests from createNext -> nextTestSetup (#93799) ## What? Converts more tests that use `createNext` to `nextTestSetup` Follow-up to #93767 --------- Co-authored-by: Cursor <cursoragent@cursor.com>github.com-vercel-next.js · 7da98e13 · 2026-05-18
- 0.6ETVrequest insights: derive request history and fetch data (2/5) (#93975) ## What Builds the bounded request history store on top of local spans and fetch metrics. Request Insights now keeps the last 100 requests, dedupes fetch records, and preserves raw span details for later verbose consumers. Stack: 1. request insights: record local framework spans (1/5) 2. request insights: derive request history and fetch data (2/5) ← current 3. request insights: expose dev snapshots to tools and HMR (3/5) 4. request insights: add agent diagnosis access (4/5) 5. request insights: add DevTools request panel (5/5) ## Review Focus - The request insight schema shared by server, tools, and DevTools. - Fetch cache/status mapping from existing `AppRender.fetch` spans. - Dedupe between completed fetch spans and direct fetch metrics. ## Proof In This PR - `pnpm jest packages/next/src/server/lib/trace/request-insights.test.ts packages/next/src/server/lib/patch-fetch.test.ts --runInBand` - `pnpm --filter=next types` ## Deferred Coverage - Browser/HMR transport, CLI/MCP access, and the visual panel are later PRs. <!-- NEXT_JS_LLM_PR --> --------- Co-authored-by: Tim Neutkens <tim@timneutkens.nl>github.com-vercel-next.js · 510d00b5 · 2026-07-12
- 0.5ETVFix instant validation blocking navigations (#95939) ### What? - Run development instant validation only after the navigation response has finished. - Let a newer request supersede stale validation work and yield between validation render attempts. - Forward the cancellation signal into React validation prerenders so asynchronous validation work can stop promptly. - Add focused scheduler/response tests and assert that development validation starts after the response finishes. ### Why? Instant validation was detached from the response promise, but its additional React renders still ran on the same Node.js event loop. A subsequent navigation could therefore wait hundreds of milliseconds for stale diagnostic work from the previous request. Instant validation still runs when the server is idle. When another navigation arrives, foreground request work now takes priority and the obsolete validation is discarded. ### How? Each Cache Components development request receives a validation generation signal. Starting a newer request aborts the previous generation. Validation waits for the Node response `finish` event, yields through the event-loop poll phase between attempts, and combines the generation signal with React's existing prerender abort signals. Tests: - `pnpm --filter=next build` - `pnpm --filter=next types` - `pnpm exec jest --runTestsByPath packages/next/src/server/app-render/dev-validation-scheduler.test.ts packages/next/src/server/app-render/wait-for-response.test.ts` - `NEXT_SKIP_ISOLATE=1 NEXT_TEST_PREFER_OFFLINE=1 pnpm test-dev-turbo test/e2e/app-dir/instant-validation/suspense-boundaries.test.ts -t "valid - static prefetch - suspense around runtime and dynamic"` <!-- NEXT_JS_LLM_PR -->github.com-vercel-next.js · 81d0e851 · 2026-07-21
- 0.4ETVAdd a benchmark for dev Cache Components validation on a worker thread (#96152) This adds `bench/dev-validation/`, wired as `pnpm bench:dev-validation`, which measures how much dev-mode Cache Components validation contends for the dev server's event loop during rapid navigation, and how much running it on a worker thread relieves that. It toggles `experimental.devValidationWorker` (added in the previous commit) to A/B the two configurations on the same build. Until the worker implementation lands the flag is inert and the A/B shows no delta. The fixture generates one route per family (`client`, `server`, `sprite`), each nested several layout segments deep under a `(routes)` route group. Validation renders a combined payload at every URL depth, so a deeper route means more validation work per navigation, which mirrors a realistically deep app rather than a single flat segment. The runner clicks a family's `<Link>` repeatedly, since navigating to the current route re-renders and re-validates it on every click. The routes carry no `instant` config because dev validation applies to page segments by default at the warning level. The three families isolate the client prerender, the Flight re-encode plus owner-stack work, and the Flight payload size, respectively. The signal is browser-observed TTFB taken from Playwright's own network timing, because it includes the time a request waits for the event loop while validation monopolizes it. We deliberately do not use the CLI's logged request durations: the dev server starts that clock inside the request handler, after the loop has already yielded to the request, so the queue wait is invisible to it. The runner prints each configuration's absolute TTFB (p50/p95/max) side by side rather than a ratio. The time the worker frees is the validation render's CPU, which is bounded, route-dependent, and does no IO, so a ratio would overstate a win that does not scale with total request time. Because the clicks are back-to-back the numbers are a worst case — navigations that land inside the validation window — and the `max` tail is the honest headline: it is the main-thread stall the worker removes.github.com-vercel-next.js · 59cc6420 · 2026-07-25
- 0.4ETVClassify Instant Insights as internal in Request Insights (#96147) ## Summary - Classifies Instant Insights records as internal and hides them by default. - Adds a persisted “Internal activity” toggle. - Nests internal records below their matching foreground request. - Preserves orphaned internal records exactly once. - Signals hidden internal errors without littering the main request list. - Raw endpoint and CLI data remain complete; filtering is UI-only. ## Verification ```bash pnpm build-all pnpm --filter=next types pnpm --filter=next build pnpm test-unit --runTestsByPath packages/next/src/next-devtools/dev-overlay/components/request-insights/trace-viewer.test.ts pnpm test-dev-turbo test/development/app-dir/request-insights/request-insights.test.ts pnpm test-dev-webpack test/development/app-dir/request-insights/request-insights.test.ts ``` <!-- NEXT_JS_LLM -->github.com-vercel-next.js · 925edc3d · 2026-07-28
- 0.4ETVFix Turbopack worker chunk loading with asset prefix (#96636) ## Summary - propagate the effective worker asset prefix through the worker bootstrap so runtime chunk registration and loading use the same base path - verify workers execute with both explicit and empty `turbopackWorkerAssetPrefix` overrides - add coverage for the Resvg WASM worker reproduction Fixes #96613 ## Verification - `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-start-turbo test/e2e/turbopack-worker-asset-prefix/turbopack-worker-asset-prefix.test.ts` - `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-dev-turbo test/e2e/turbopack-worker-asset-prefix/turbopack-worker-asset-prefix.test.ts` - Resvg WASM worker test in production and development Turbopack - focused `turbopack-tests` worker and ignore-comments snapshots - `pnpm swc-build-native` - Full `pnpm build-all` did not complete locally because of unrelated existing `httpxy` and proxy-request type errors <!-- NEXT_JS_LLM --> --------- Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>github.com-vercel-next.js · 7577fa3c · 2026-08-05
- 0.4ETVTurbopack: support import.meta.glob caseSensitive option (#96226) ## Summary Add Vite-compatible `caseSensitive` support to `import.meta.glob()`. Matching remains case-sensitive by default, while `caseSensitive: false` applies case-insensitive matching to directory traversal, filenames, positive patterns, and negative patterns. The option is included in matcher equality and non-default virtual module identity, and is exposed through diagnostics, TypeScript declarations, and the Turbopack options reference. ## Verification - `cargo test -p turbo-tasks-fs glob` - `cargo nextest run -p turbopack-tests -E "test(import_meta_glob) and not test(import_meta_glob_errors)"` - `cargo fmt --all -- --check` - `pnpm build-all` and `pnpm --filter=next types` are blocked by current-canary `sharp.default` type errors in `packages/next/src/server/image-optimizer.ts` <!-- NEXT_JS_LLM -->github.com-vercel-next.js · 3f2cf7e1 · 2026-07-26
- 0.4ETVrequest insights: expose dev snapshots to tools and HMR (3/5) (#93976) ## What Adds the `experimental.requestInsights` flag, a private dev snapshot endpoint, and HMR snapshot/update transport so running dev servers can expose recent request insights to tools and browser clients. Stack: 1. request insights: record local framework spans (1/5) 2. request insights: derive request history and fetch data (2/5) 3. request insights: expose dev snapshots to tools and HMR (3/5) ← current 4. request insights: add agent diagnosis access (4/5) 5. request insights: add DevTools request panel (5/5) ## Review Focus - Dev-only gating for `experimental.requestInsights`. - Private endpoint behavior when enabled and disabled. - HMR snapshot/update shape and client-side retention. ## Proof In This PR - `pnpm --filter=next types` - Stack-tip Cache Components smoke verifies the endpoint and HMR-fed overlay state against a running dev server. ## Deferred Coverage - A dedicated isolated dev-server transport test can follow if reviewers want cheaper per-PR coverage than the stack-tip smoke. <!-- NEXT_JS_LLM_PR --> --------- Co-authored-by: Tim Neutkens <tim@timneutkens.nl>github.com-vercel-next.js · 31541356 · 2026-07-12
- 0.4ETVfeat(turbopack): support import.meta.env (#96225) ## Summary - add native Turbopack support for `import.meta.env.DEV`, `PROD`, `MODE`, `BASE_URL`, and `SSR` - statically analyze built-in values for dead-code elimination while exposing the complete runtime object - derive `BASE_URL` from the Next.js `basePath` and include Vite-compatible trailing-slash formatting - add TypeScript declarations, focused execution and Next.js integration coverage, and Vite migration documentation ## Verification - `cargo fmt --all -- --check` - `cargo nextest run -p turbopack-tests -E 'test(import_meta_env)'` - `pnpm build-all` - `pnpm --filter=next types` - `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-dev-turbo test/e2e/import-meta-env/import-meta-env.test.ts` - `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-start-turbo test/e2e/import-meta-env/import-meta-env.test.ts` <!-- NEXT_JS_LLM -->github.com-vercel-next.js · c23d1a94 · 2026-07-28
- 0.3ETVPersist Request Insights display settings (#96277) ## Summary - Replaces the per-request verbose checkbox with a global Request Insights settings menu. - Persists `requestInsights.verbose` through the existing DevTools configuration path. - Restores the setting across reloads. - Does not include the unrelated global `pagehide` flush behavior. ## Verification ```bash pnpm build-all pnpm --filter=next types pnpm --filter=next build pnpm test-dev-turbo test/development/app-dir/request-insights/request-insights.test.ts pnpm test-dev-webpack test/development/app-dir/request-insights/request-insights.test.ts ``` <!-- NEXT_JS_LLM -->github.com-vercel-next.js · c294cb75 · 2026-07-28
- 0.3ETVEnable TypeScript CLI by default (#96497) ## Summary Enable the project-local TypeScript CLI checker by default during `next build`, while preserving `experimental.useTypeScriptCli: false` as an opt-out to the TypeScript compiler API. Update the TypeScript 7 guidance, diagnostics, tests, and documentation to match the new default. ## Verification - `pnpm exec jest --runTestsByPath test/unit/isolated/config.test.ts` - Pre-commit lint-staged checks passed (Prettier and ESLint) - Not run: `pnpm test-start-turbo test/production/app-dir/typescript-cli/typescript-cli.test.ts` (isolated fixture dependency installation was blocked by unavailable npm registry access) - Not run: `pnpm --filter=next types` (repository has pre-existing unrelated TypeScript errors) <!-- NEXT_JS_LLM -->github.com-vercel-next.js · cbf0cef6 · 2026-08-03
- 0.3ETVrequest insights: add agent diagnosis access (4/5) (#93977) ## What Adds `next experimental-diagnose` and an MCP `get_request_insights` tool so agents and local users can inspect Request Insights without opening the DevTools overlay. Stack: 1. request insights: record local framework spans (1/5) 2. request insights: derive request history and fetch data (2/5) 3. request insights: expose dev snapshots to tools and HMR (3/5) 4. request insights: add agent diagnosis access (4/5) ← current 5. request insights: add DevTools request panel (5/5) ## Review Focus - CLI error handling and raw JSON output. - MCP gating when Request Insights is unavailable. - Telemetry registration for the new MCP tool name. ## Proof In This PR - `pnpm jest packages/next/src/telemetry/events/mcp-telemetry.test.ts --runInBand` - `pnpm --filter=next types` - Stack-tip smoke verifies `next experimental-diagnose --url http://localhost:3003 --json` against a real dev server. ## Deferred Coverage - A more curated agent summary format is intentionally deferred until the raw private snapshot contract settles. <!-- NEXT_JS_LLM_PR --> --------- Co-authored-by: Tim Neutkens <tim@timneutkens.nl>github.com-vercel-next.js · 4a4590a3 · 2026-07-13
- 0.3ETVRevert "Revert "refactor: write pages router export files directly to server/pages/"" (#93409) Re-apply #92735 Before re-landing we need to investigate why the pages router middleware i18n test fails when deployed. Update: Investigation/fix: https://github.com/vercel/next.js/pull/92735#issuecomment-4242978559 Reverts vercel/next.js#92733 --- Cursor plan based on the investigation Claude did: # Fix i18n export orphan HTML files in server/pages/ ## Problem When i18n is configured, the export path map in `build/index.ts` creates locale-prefixed entries for every page (e.g., `/en/home/a`, `/fr/home/a`), but only deletes the non-locale entry from `defaultMap` for SSG pages. For non-SSG static pages, the non-locale entry (e.g., `/home/a`) remains, causing the export worker to render and write orphan HTML files directly to `server/pages/`. These orphan files interfere with routing on deployment platforms (e.g., a `[teamId]/[slug].html` orphan matches rewritten paths that should 404). ## Root Cause In [packages/next/src/build/index.ts](packages/next/src/build/index.ts) at line 2988: ```2988:2991:packages/next/src/build/index.ts if (isSsg) { // remove non-locale prefixed variant from defaultMap delete defaultMap[page] } ``` The `if (isSsg)` guard means non-SSG pages keep their non-locale entry, which gets rendered and written to `server/pages/` as an orphan file. ## Fix **Single-line change** in [packages/next/src/build/index.ts](packages/next/src/build/index.ts): Remove the `if (isSsg)` guard so `delete defaultMap[page]` always runs when i18n is enabled. The locale-prefixed entries are already created in the loop above (line 2981), and they capture the original `page` value via `defaultMap[page]?.page || page`. The non-locale entry is not needed after that -- in the old staging-directory flow (`moveExportedPage`), it was rendered but never moved to the final output directory. **Safety verification:** - `updatePagesManifestForExportedPage` (line 3754) is called based on `combinedPages`, not the export map -- it still correctly replaces non-locale manifest entries with locale-prefixed ones - `pageDuration` tracking (line 3745) may return `undefined` for the non-locale path, but this is typed `number | undefined` and used with `|| 0` fallback at line 375 of `build/utils.ts` -- purely cosmetic - SSG pages already have this exact behavior (delete from defaultMap), so this change makes non-SSG consistent with SSG - The `ssgPageDurations` invariant check (line 3737-3738) only runs for SSG pages, which are unaffected ## Test Add assertions to the existing i18n integration test at [test/integration/i18n-support/test/index.test.ts](test/integration/i18n-support/test/index.test.ts) to verify that non-locale-prefixed HTML orphans do not exist in `server/pages/` after build. The test already has production mode assertions checking locale-prefixed file existence and manifest correctness (lines 81-99).github.com-vercel-next.js · c7a5a095 · 2026-05-26
- 0.3ETVKeep the request body a plain Readable after middleware so Readable.toWeb() doesn't hang (#95607) Recreation of https://github.com/vercel/next.js/pull/95370 ### What's the problem? A `POST` (or `PUT`/`PATCH`) request that passes through middleware returning `NextResponse.next()` hangs indefinitely when the downstream handler reads the body via Node's `Readable.toWeb()`. The request never completes and eventually times out. Reproduction: https://github.com/abir-taheer/next-js-readable-stream-bug ### Root cause When middleware runs, `runMiddleware` clones the request body and later calls `finalize()`, which grafts the buffered stream back onto the original `IncomingMessage` via `replaceRequestBody()` (`packages/next/src/server/body-streams.ts`). `replaceRequestBody` copies the buffered stream's enumerable properties onto the request. The buffered stream (`p2`) was a `PassThrough` — a `Duplex` — so its writable-side internals (`_writableState` plus the enumerable `Writable` methods like `write`/`end`) were copied onto the `IncomingMessage`. Because that `_writableState.finished` is `false`, Node stream utilities that inspect it — including `Readable.toWeb()`, which uses `finished()`/end-of-stream detection — treat the request as a still-open writable stream and wait forever. `NextResponse.rewrite()` is unaffected (it builds a new internal request and skips this path), and `GET`/`HEAD` requests are fine because there is no body to clone. ### The fix `p2` is only ever fed with `.push()`, so it never needs a writable side. Making it a plain `Readable` instead of a `PassThrough` keeps the finalized request a pure `Readable`, so `Readable.toWeb()` (and any other duck-typing based on `_writableState`) behaves correctly. No behavior change for the existing consumers, which only read the stream. ### Testing Added `test/unit/body-streams.test.ts`, which drives the real clone → `finalize()` flow and asserts the finalized request: - is no longer writable (`_writableState` is `undefined`), and - is fully consumable via `Readable.toWeb()` (this hangs before the fix). Fixes #95335 <!-- NEXT_JS_LLM_PR --> Co-authored-by: UditDewan <udit.dewan21@gmail.com> Co-authored-by: Baradhan-Madhu <26barum@gmail.com>github.com-vercel-next.js · 3bb780e7 · 2026-07-10
- 0.3ETVIsolate local Request Insights spans from OpenTelemetry (#96276) ## Summary - Keeps Request Insights diagnostic spans inside the local recorder. - Nested generic Next.js spans retain the local parent hierarchy. - The user’s active OpenTelemetry context remains active and unchanged. - Diagnostic wrappers are not delegated to or exported through user OpenTelemetry. ## Verification ```bash pnpm build-all pnpm --filter=next types pnpm --filter=next build pnpm test-unit --runTestsByPath packages/next/src/server/lib/trace/local-span-recorder.test.ts packages/next/src/server/lib/trace/tracer.test.ts ``` <!-- NEXT_JS_LLM -->github.com-vercel-next.js · 77169764 · 2026-07-28