Skip to content

[pull] canary from vercel:canary - #1303

Merged
pull[bot] merged 10 commits into
code:canaryfrom
vercel:canary
Aug 14, 2026
Merged

[pull] canary from vercel:canary#1303
pull[bot] merged 10 commits into
code:canaryfrom
vercel:canary

Conversation

@pull

@pull pull Bot commented Aug 14, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

aurorascharff and others added 10 commits August 14, 2026 09:55
## Summary

### Original issue

Pages API functions produced through a build adapter can fail during
function initialization, before the customer handler executes:

```
Cannot find module 'next/dist/compiled/next-server/pages-turbo.runtime.prod.js'
```

The failure is triggered when an externalized dependency used by the API
route imports a Next.js module such as `next/head`. At runtime the load
path is:

```
external dependency
  -> next/head
  -> head-manager-context.shared-runtime
  -> Pages vendored head-manager context
  -> pages/module.compiled.js
  -> pages[-turbo].runtime.prod.js
```

The two important edges at the end of this chain are selected
dynamically. The Next.js require hook redirects the shared-runtime
import to the Pages vendored context, and `pages/module.compiled.js`
selects the bundler-specific production renderer. As a result, a Pages
API entry trace does not discover the regular Pages renderer. It
naturally contains `pages-api[-turbo].runtime.prod.js`, which is the
runtime for the API route module, but not
`pages[-turbo].runtime.prod.js`, which is reached through the external
`next/head` import.

This is why the failure is specific to Pages API routes. A regular Pages
SSR entry already references and traces the Pages renderer. App Router
entries use different route modules and traces.

### Fix

Trace the hidden Pages renderer dependency using the mechanism
appropriate to each bundler:

- **Turbopack:** add `pages-turbo.runtime.prod.js` as an explicit entry
in `Project::pages_traced_modules`. The existing native Turbopack module
graph then traces its full runtime closure. This does not run Node File
Trace and remains scoped to Pages endpoints.
- **Webpack:** run the existing Node File Trace path on
`pages.runtime.prod.js` and merge that closure into the Pages shared
assets. This code remains inside the non-Turbopack branch.

The existing require-hook modules remain separate, and App Router or
neutral endpoint trace sets are unchanged. No adapter change is
required.

### Regression test

The fixture externalizes a package that imports `next/head`, matching
the reported dependency boundary. The test builds with an adapter,
materializes only the generated Pages API function entry and its
provided assets into a clean directory, initializes the production
environment, and requires the handler in a child process.

This verifies the observable initialization behavior under both
Turbopack and Webpack rather than asserting a particular output file
list.

## Verification

- `cargo check -p next-api`
- `pnpm --filter=next build`
- `pnpm test-start-turbo
test/production/adapter-pages-api-runtime/adapter-pages-api-runtime.test.ts`
- `pnpm test-start-webpack
test/production/adapter-pages-api-runtime/adapter-pages-api-runtime.test.ts`

<!-- NEXT_JS_LLM -->

Co-authored-by: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com>
The `use-cache-private` suite covered private caches in server
components only, so this adds a route handler that calls one `'use
cache: private'` function three times: a concurrent pair, and a third
call after a short delay. The concurrent pair joins a single in-flight
invocation, while the delayed call lands after the map of pending
intra-request invocations has dropped its entry, so it is served from
the completed entry that the request retains. Each call passes a fresh
object literal, which makes the React `cache()` memo miss on reference
equality so that the lookup falls through to the serialized cache key.
The cache function also reads a cookie, which covers that request APIs
are allowed inside a private cache in a route handler.

A second test asserts that nothing is shared across requests. In
production private entries are neither persisted nor deduped across
requests, so every request re-runs the cache function. In development
they are persisted and forced to `revalidate: 0`, so the next request is
served the stale entry while a fresh one warms in the background, which
the dev branch of the test follows. Both tests pass their own `id`
search param, and therefore use their own cache key, so the entry that
dev persists for one is never served to the other.

This also drops the claim that the directive is not available in route
handlers from the `'use cache: private'` reference. Nothing in the
source rejects it, and it was already allowed for request work unit
stores when that note was written.
…97350)

Adopts #97150. Closes #97150.

Fixes #96859

### What?

Since 16.3.0, builds fail for pages-router files named `sitemap` or
`robots` that export `getStaticProps`/`getServerSideProps`:

```
Error: "getStaticProps" is not supported in app/.
```

This is a regression from #94962, which added the metadata conventions
(`sitemap`, `robots`, `manifest`, `icon`, …) to the app-entry filename
regex in `ReactServerComponentValidator::assert_invalid_api`. The regex
only looks at the filename, so a file like `pages/sitemap.js` is now
mistaken for an app entry and rejected for exporting `getStaticProps`.

### How?

A file is only treated as an app entry when it's inside `appDir`,
reusing the gate `assert_server_filename` already applies to `error.js`.
The pages compilation context has no `appDir`, so pages-router files are
never validated as app entries.

On the test side:

- The fixtures that exercise the app-entry checks moved under
`app-dir/`, since the test harness derives `appDir` from the fixture
path. Their contents are unchanged.
- A new fixture (plus a `sitemap.js` fixture glob) asserts that a
pages-style `sitemap.js` compiles without errors.
- A new e2e suite, `test/e2e/pages-metadata-filenames`, covers
`pages/sitemap.js` with `getStaticProps` and `pages/robots.js` with
`getServerSideProps`. It fails without the fix under Turbopack (build
and dev) and passes with it under both Turbopack and webpack.

Supersedes #96873 (same approach, closed by its author) and closes
#96967.

---------

Co-authored-by: Rodrigo Arias <rodrigo@arias.me>
## Summary

- trace the primary App Router and Pages Router route-module load inside
`loadComponents`
- expose `LoadComponents.loadRouteModule` as the default `load route
module` OpenTelemetry span
- verify the span in development and production with both Turbopack and
Webpack

## Why

Route-module evaluation can account for cold request time before route
preparation and rendering begin. Keeping this boundary in the Next.js
server makes it available to `next dev`, self-hosted `next start`,
direct entrypoints, and deployment integrations without depending on an
adapter-specific launcher.

The span wraps only the requested route module. It does not include
`_app`, `_document`, rendering, or any adapter launcher work, and it
does not add filesystem paths, raw URLs, or other high-cardinality
attributes.

## Verification

- `pnpm build-all`
- `pnpm --filter=next build`
- `pnpm --filter=next types`
- `pnpm exec jest packages/next/src/server/lib/trace/tracer.test.ts
--runInBand`
- focused OpenTelemetry E2E in `test-dev-turbo`, `test-dev-webpack`,
`test-start-turbo`, and `test-start-webpack`
- Prettier, ESLint, and `git diff --check`
## Summary

- trace the full route-module preparation boundary as
`RouteModule.prepare`
- record manifest loading as one aggregate `RouteModule.loadManifests`
child span
- keep route preparation visible by default while exposing manifest
detail only with verbose tracing
- cover normal and direct-entrypoint server lifecycles without relying
on test ordering

## Why

Route preparation is the stable boundary between loading a route module
and executing it. The parent span shows the total setup cost; the
aggregate manifest child explains manifest work without creating
per-file spans or exposing paths.

## Verification

- `pnpm build-all`
- `pnpm --filter=next build`
- `pnpm --filter=next types`
- `pnpm exec jest packages/next/src/server/lib/trace/tracer.test.ts
--runInBand`
- focused OpenTelemetry E2E in development and production with Turbopack
and Webpack
- Request Insights route-preparation E2E with Turbopack and Webpack
- Prettier, ESLint, and `git diff --check`

## Stack

Depends on **Trace route module loading**.
## Summary

- trace instrumentation module loading and `register()` execution as
separate startup spans
- preserve the original timestamps when the OpenTelemetry provider is
installed by `register()` itself
- export both lifecycle spans by default without attaching them to an
unrelated request
- verify standard and direct-entrypoint startup with a collector
connected before the server starts

## Why

Loading `instrumentation.ts` and running the user-defined `register()`
hook have different owners and remediation paths. Separate spans make
startup delays attributable while preserving honest lifecycle parentage:
these spans normally occur before a request identity exists.

## Verification

- `pnpm build-all`
- `pnpm --filter=next build`
- `pnpm --filter=next types`
- `pnpm exec jest packages/next/src/server/lib/trace/tracer.test.ts
--runInBand`
- focused instrumentation-startup E2E in development and production with
Turbopack and Webpack
- Prettier, ESLint, and `git diff --check`

## Stack

Depends on **Trace route module preparation**.
@pull pull Bot locked and limited conversation to collaborators Aug 14, 2026
@pull pull Bot added the ⤵️ pull label Aug 14, 2026
@pull
pull Bot merged commit d8be6c5 into code:canary Aug 14, 2026
11 of 14 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants