### What?
Adds a `compile_route` MCP tool that triggers on-demand compilation of a
specific route (app or pages) without issuing an HTTP request, and
returns any compilation issues.
### Why?
Coding agents and benchmarking workflows need a way to warm the module
graph or measure compile time for a route without standing up a live
backend to satisfy the request. The existing path — hitting the URL —
requires the route's runtime dependencies to be available and couples
compile timing to request handling.
### How?
- New tool `mcp/compile_route` registered in
`get-or-create-mcp-server.ts`, backed by a `compileRoute({ page,
clientOnly })` callback plumbed from the Turbopack hot reloader
- Reuses the dev server's existing on-demand entry path (`ensurePage` /
`handleRouteType`), so the call path matches a first navigation.
- Adds a `subscribeToChanges` opt-out on `ensurePage` and threads it
through `handleRouteType` / `handlePagesErrorRoute`. One-shot MCP
compilations skip HMR subscription wiring — without this, each call
would leak a subscription that fires on every subsequent file change for
the life of the dev server.
- Telemetry: registers `mcp/compile_route` in the `McpToolName` union.
- e2e test in
`test/development/mcp-server/mcp-server-compile-route.test.ts`.
<!-- NEXT_JS_LLM_PR -->
### What?
Move the validation that can produce `CssModuleComposesIssue` from code
generation (`chunk_item_content`) to the reference's own
`resolve_reference()` method, so these errors are surfaced during
resolving rather than only during bundling.
Two validation checks are moved into
`CssModuleComposeReference::resolve_reference()`:
1. A `composes: ... from "...";` target module can't be resolved
(unresolvable reference)
2. A `composes: ... from "...";` target module is not a CSS module (e.g.
composing from a `.js` or `.txt` file)
The `IssueStage` is updated from `CodeGen` to `Resolve` to reflect the
new phase.
Code generation still handles the error cases gracefully (skipping
broken references with `continue`) — it just no longer re-emits the
issue since it is already emitted by `resolve_reference()`.
### Why?
`get_compilation_issues` (used by the MCP server and other tooling) only
builds the module graph — it does not run code generation. Previously,
both `CssModuleComposesIssue` variants were only emitted during
`chunk_item_content()`, which meant they were invisible to
`get_compilation_issues`. Developers using the MCP
`get_compilation_issues` tool would not see errors from broken
`composes` references until an actual build/bundle was triggered.
Since `resolve_reference()` is called as part of module graph traversal,
emitting the issue there means it is captured by
`get_compilation_issues` alongside other resolve-phase errors.
### How?
**`turbopack-css/src/references/compose.rs`**
- `CssModuleComposeReference::resolve_reference()` is changed from `fn`
to `async fn`. It calls `css_resolve` as before, then awaits
`first_module()` on the result and validates:
- Resolved to nothing → emit "can't be resolved" issue
- Resolved to a module that doesn't implement `CssModuleComposable` →
emit "not a CSS module" issue
- `CssModuleComposesIssue` and its `Issue` impl are moved here from
`module_asset.rs`, now using `ResolvedVc<FileSystemPath>` (from
`origin_path()`) as the issue location rather than the `IssueSource` of
the composing file.
- A new `CssModuleComposable` marker trait
(`#[turbo_tasks::value_trait]`) is defined here. `resolve_reference()`
uses a `try_sidecast` to this trait to check whether the resolved module
is a valid compose target — avoiding a hard dependency on
`EcmascriptCssModule` from within `compose.rs`.
**`turbopack-css/src/module_asset.rs`**
- `EcmascriptCssModule` implements `CssModuleComposable`, marking it as
a valid `composes:` target.
- `module_references()` is reverted to its original simple form — it
only collects references without any validation.
- All issue-related imports (`Issue`, `IssueExt`, `IssueSource`, etc.)
are removed.
**Test fixtures**
(`test/development/mcp-server/fixtures/compilation-errors-app/app/css-composes-error/`)
- `styles.module.css` — CSS module with `composes: something from
'./not-a-css-module.txt'`
- `not-a-css-module.txt` — a plain text file (resolves but is not a CSS
module)
- `page.tsx` — page importing the broken CSS module
**`test/development/mcp-server/mcp-server-get-compilation-issues.test.ts`**
- New test case `should detect CSS module composes errors` verifies the
issue is surfaced via `get_compilation_issues`.
<!-- NEXT_JS_LLM_PR -->
---------
Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
These tests won't ever be run in a deployed environment, so this removes
`skipDeployment` so it's easier to grok which tests are intentionally
disabled because they don't work when deployed.
### What?
Adds a new \`get_compilation_issues\` MCP tool (and the underlying
\`projectGetAllCompilationIssues\` NAPI method) that returns all
compilation issues from all routes in a single call.
**New files:**
- \`crates/next-napi-bindings/src/next_api/project.rs\` —
\`project_get_all_compilation_issues\` NAPI function +
\`get_all_compilation_issues_operation\` /
\`get_all_compilation_issues_inner_operation\` turbo-tasks operations
- \`packages/next/src/server/mcp/tools/get-compilation-issues.ts\` — MCP
tool implementation
-
\`packages/next/src/server/mcp/tools/utils/format-compilation-issues.ts\`
— output formatter
-
\`test/development/mcp-server/mcp-server-get-compilation-issues.test.ts\`
— e2e test
- \`test/development/mcp-server/fixtures/compilation-errors-app/\` —
fixture app with three routes (valid page, missing-module error, syntax
error)
**Modified files:**
- \`packages/next/src/build/swc/generated-native.d.ts\` + \`types.ts\` +
\`index.ts\` — expose the new NAPI method
- \`packages/next/src/server/mcp/get-or-create-mcp-server.ts\` —
register the new tool, accept \`getTurbopackProject\` option
- \`packages/next/src/server/dev/hot-reloader-turbopack.ts\` — pass
\`project\` to MCP middleware
- \`packages/next/src/telemetry/events/build.ts\` — add
\`'mcp/get_compilation_issues'\` to the \`McpToolName\` union
### Why?
The existing MCP tools require a browser session (and thus a specific
route to be rendered) to surface compilation errors.
\`get_compilation_issues\` works without a browser session and covers
all routes proactively — useful for AI coding agents that want to check
for errors across the whole app before trying to render a page.
### How?
**NAPI layer:**
\`project_get_all_compilation_issues\` calls a two-level turbo-tasks
operation pair:
1. \`get_all_compilation_issues_inner_operation\` — iterates all
endpoint groups via \`project.get_all_endpoint_groups(false)\` and calls
\`endpoint_group.module_graphs().as_side_effect()\` on each. This builds
the module graph (resolution + transformation) for every entrypoint
without chunking, emitting, or code generation. Issues are emitted as
turbo-tasks collectables.
2. \`get_all_compilation_issues_operation\` — wraps the inner op in
\`strongly_consistent_catch_collectables\` to harvest
issues/diagnostics/effects, then returns an \`OperationResult\`.
> **Why not \`project.whole_app_module_graphs()\`?**
> \`whole_app_module_graphs()\` calls \`drop_issues()\` in development
mode to prevent every per-route HMR subscription from seeing all global
issues. Calling it here would return zero issues in dev. Per-endpoint
\`module_graphs()\` calls don't have this suppression.
**Output formatting (\`format-compilation-issues.ts\`):**
The raw Turbopack wire types are transformed before being returned to
MCP consumers:
- **StyledString → plain string**: \`title\`, \`description\`, and
\`detail\` are \`StyledString\` union trees (recursive \`{type, value}\`
objects). These are flattened to plain strings —
\`text\`/\`code\`/\`strong\` variants return their \`.value\` directly,
\`line\` joins with \`""\`, \`stack\` joins with \`"\n"\`.
- **ANSI codes stripped**: \`codeFrame\` is a pre-rendered string from
the Rust NAPI layer that contains ANSI terminal colour codes. These are
stripped via \`next/dist/compiled/strip-ansi\`.
- **1-indexed source positions**: Turbopack's \`SourcePos\` is 0-indexed
for both \`line\` and \`column\`. The formatter adds \`+1\` to each so
consumers get the conventional editor-style 1-indexed values.
- **Deduplication**: the same issue can surface from multiple endpoints
during the module graph traversal. Issues are deduplicated by a
\`severity|filePath|title|startLine:startCol\` key.
- **No diagnostics**: Turbopack diagnostics are internal telemetry
(\`EVENT_BUILD_FEATURE_USAGE\` feature-adoption counters). They are not
actionable for the user, so the \`diagnostics\` field is omitted
entirely from the response.
**MCP tool (\`get_compilation_issues\`):**
Calls \`project.getAllCompilationIssues()\`, passes the issues through
\`formatCompilationIssues()\`, and returns \`{ issues: FormattedIssue[]
}\` as JSON. Works without a browser session.
**Test:**
A fixture app with three routes (valid \`app/page.tsx\`,
\`app/missing-module/page.tsx\` importing a non-existent package,
\`app/syntax-error/page.tsx\` with unclosed JSX) is used to verify:
1. The tool returns a result without any browser session
2. Module-not-found errors are detected
3. Syntax errors are detected
4. Issues include \`severity\`, \`title\`, \`filePath\` metadata — all
as plain strings (not StyledString objects)
e2e tests: added —
\`test/development/mcp-server/mcp-server-get-compilation-issues.test.ts\`
---------
Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Rspack now enables persistent caching by default.
## Performance Comparison
### Pages Router
I benchmarked performance using this repo:
https://github.com/SyMind/chakra-ui-docs/tree/next-rspack to test the
Next.js pages router.
I tested the performance with the following steps:
1. Execute `pnpm run dev`
2. Wait for the server to be ready (indicated by the 'Ready' message)
3. Run curl on the root endpoint (/)
Each build was run 5 times, and the shortest time to reach "Compiled
successfully" was recorded.
Test environment: Apple M1 Pro CPU
| Tool | Build without cache | Build with cache | Dev without cache |
Dev with cache |
|-------------|---------------------|------------------|---------------------------------|----------------|
| Rspack | 3.8s | 2.6s | 1.7s | 3ms |
| Webpack | 14.0s | 4.0s | 7.8s | 3.2s |
### App Router
I benchmarked performance using this repo:
https://github.com/SyMind/shadcn-ui/tree/next-rspack to test the Next.js
app router.
I tested the performance with the following steps:
1. Execute `pnpm run dev` or `pnpm run build`
2. Wait for the server to be ready (indicated by the 'Ready' message)
3. Run curl on the root endpoint (/)
Each build was run 5 times, and the shortest time to reach "Compiled
successfully" was recorded.
Test environment: Apple M1 Pro CPU
| Bundler | Build (No Cache) | Build (Cache) | Dev (No Cache) | Dev
(Cache) |
|------------|----------------------|-------------------|--------------------|-----------------|
| Rspack | 12.3s | 5.9s | 7.1s | 1941ms |
| Webpack | 27.0s | 13.0s | 11s | 9.6s |
## About Rspack Persistent Cache Strategy
> packages/next/src/server/dev/hot-reloader-rspack.ts
Rspack's persistent caching differs from Webpack in how it manages
module graphs. While Webpack incrementally updates modules, Rspack
operates on complete module graph snapshots for cache restoration.
Problem:
- Next.js dev server starts with no page modules in the initial entry
points
- When Rspack restores from persistent cache, it finds no modules and
purges the entire module graph
- Later page requests find no cached module information, preventing
cache reuse
Solution:
- Track successfully built page entries after each compilation
- Restore these entries on dev server restart to maintain module graph
continuity
- This ensures previously compiled pages can leverage persistent cache
for faster builds
## Note
I have updated the test case configuration in
`test/integration/telemetry/next.config.use-cache` to disable persistent
cache.
This is because, whether using webpack or Rspack, when persistent
caching is enabled, modules are no longer recompiled by loaders, which
prevents the Telemetry plugin from collecting information.
Please note that this issue also exists with webpack. You can reproduce
it locally by running `pnpm run test
test/integration/telemetry/test/config.test.js` twice.
update @next/rspack-core version to 1.0.2 and update the snapshot
other changes:
- packages/next/src/build/webpack-config.ts
Adjusted configuration to account for differences in default node config
between Rspack and Webpack.
- packages/next/src/shared/lib/format-webpack-messages.ts
Added a fallback to moduleIdentifier in cases where Rspack does not
correctly populate moduleName.
### What?
Adds build-time validation to require explicit `default.js` files for
all parallel route slots (except the implicit "children" slot). This
validation is implemented in both Webpack and Turbopack bundlers.
### Why?
Parallel routes without `default.js` files currently cause silent 404
errors when users navigate to those routes. This creates confusion and
hard-to-debug issues because the routes appear to be configured
correctly but fail at runtime without any indication of what went wrong.
By making this validation explicit at build time, developers get
immediate feedback about missing required files with clear error
messages and documentation links, catching configuration mistakes before
deployment.
### How?
**Rust/Turbopack** (`crates/next-core/src/app_structure.rs`): Added
`MissingDefaultParallelRouteIssue` that emits a build error when a
parallel route slot is missing its `default.js` file. The validation is
skipped for the "children" slot since it's implicit and doesn't require
a default file.
**Webpack**
(`packages/next/src/build/webpack/loaders/next-app-loader/index.ts`):
Added validation that throws `MissingDefaultParallelRouteError` when
`default.js` cannot be resolved. The "children" slot falls back to the
existing `PARALLEL_ROUTE_DEFAULT_PATH` behavior for backward
compatibility.
**Error Class**
(`packages/next/src/shared/lib/errors/missing-default-parallel-route-error.ts`):
New error type with helpful messaging that includes the slot path,
explanation of the requirement, and a link to documentation.
**Migration Path**: Users who want the previous 404 behavior can
explicitly create a `default.js` that calls `notFound()`, or return
`null` for empty slots:
```tsx
import { notFound } from 'next/navigation'
export default function Default() {
notFound()
}
```
Users can also run the following Deno script to generate the default
files for them:
https://gist.github.com/wyattjoh/ba7263ecb637ef399d3e3e4db63ffbd6
**Breaking Change**: This is a breaking change timed for Next.js 16
beta. Builds will now fail if parallel route slots are missing required
`default.js` files.
The `get_page_metadata` MCP tool was incorrectly grouping browser
sessions by URL instead of counting each session individually. When
multiple browser tabs were open to the same URL, the tool would report
only 1 session instead of the actual number of sessions.
Enabling `experimental.isolatedDevBuild` required many changes to the
current workflow, so we will incrementally roll out to the tests.
Enabling on test-dev instead of test-experimental-dev because
`-experimental` CIs are filtered via `experimental-tests-manifest.json`
and they don't cover all tests. We want to enable this feature by
default so we should ensure this incremental rollout is covered on all
test cases.
The flag was enabled for `test-experimental-dev` at
https://github.com/vercel/next.js/pull/84099, and this PR moves the flag
to the `test-dev` job.
1. ~~test-experimental-dev
([link](https://github.com/vercel/next.js/pull/84099))~~
2. test-dev (here)
3. test-prod
4. test-integration
5. test-unit
6. Enable by default, remove the flag, and update the rest
x-ref: https://github.com/vercel/next.js/pull/84043
1. Added functionality to change the package name in the rspack release
CI.
2. Fixed a bug in the get_resolve method of the NextExternalsPlugin.
3. Prepared the @next/rspack-core for the 1.0.0 version release.
Enables AI agents to programmatically access the runtime metadata of the
current page. At the moment, we only include the segment trie details,
but this endpoint will be open to extension. Like `get_errors`, we
support collecting information from multiple tabs.
Enables AI agents to programmatically access the runtime/build errors
from the current devtool overlay of a dev session. The errors are
pretty-printed by default with source-mapped stack frames. In
particular, it supports pulling error information from multiple browser
tabs.
This PR integrates an MCP server into the Next.js development server at
`/_next/mcp`, enabling AI agents to programmatically interact with
Next.js projects. We're including an initial `get_project_path.` tool as
an example that returns the project's absolute path - this serves as a
starting point to demonstrate how tools can expose project information
to MCP clients, with plans to expand the available tools for richer
AI-assisted development experiences.