100 Commits
Author SHA1 Message Date
Jude GaoandGitHub d6f2ca8023 Preserve basePath in redirect destinations (#95608)
Fixes an edge case ([repro](https://github.com/amannn/nextjs-16-3-bug-repro-basepath)) for `experimental.validateRSCRequestHeaders`.
2026-07-21 11:36:36 -04:00
Jude GaoandGitHub 50f367bc21 Package skills/ as a Claude Code plugin (#95907)
#94877 removed the embedded plugin marketplace because its plugin
carried copies of skills that drifted from `skills/`. This re-adds
plugin packaging without duplicating any content: `skills/` itself is
the plugin root. `skills/.claude-plugin/plugin.json` sets `"skills":
["./"]` so the four skills at `skills/*/SKILL.md` are discovered in
place, and the root `.claude-plugin/marketplace.json` points its single
entry at `./skills`. External catalogs can reference the plugin with a
`git-subdir` source (`path: "skills"`), which sparse-clones only that
directory instead of the whole repo.

`claude plugin validate` passes on both manifests. `claude --plugin-dir
./skills` discovers all four skills
(`nextjs:next-cache-components-adoption`,
`nextjs:next-cache-components-optimizer`, `nextjs:next-dev-loop`,
`nextjs:next-partial-prefetching-adoption`).
2026-07-17 19:46:13 +00:00
Jude GaoandGitHub 34d92a5026 Convert agent-041's blocking-data check to the agentic LLM judge (#95630)
Make the ppr test accept diverse solutions as long as they lead to a
static shell. Achieved by `expect(environment).toSatisfyCriterion`
(a.k.a., llm-as-judge)
2026-07-09 10:13:37 -04:00
Jude GaoandGitHub eeb59c12aa Make the agent-rules block verifiable and self-upgrading (#95467)
Agents have started flagging the managed `nextjs-agent-rules` block as
prompt injection and refusing to follow or commit it (#95130). Headless
A/B evals (Claude Code + Sonnet 5, pnpm-monorepo and standalone-npm
fixtures, `[email protected]`) isolate the triggers:
`node_modules/next/dist/docs/` doesn't resolve from the workspace root
in non-hoisted installs, the "maintained by `next dev`" claim is
unverifiable, and the **Keep this block** paragraph reads as a
self-persisting instruction. The failure concentrates on the uncommitted
state a fresh `next dev` run produces.

The block now anchors the docs path to the block file's directory with a
monorepo note, and replaces the commit imperative with a verify pointer
to `generate-agent-files.js` plus the reason committing it keeps the
tree clean. This is the only change in this PR, and it was ablated in
isolation — an A/A run of the baseline first established the noise floor
(block committal 0/5, 0/8, 1/8 across three independent baseline
batches):

| Metric | Old block | New block |
|
---------------------------------------------------------------------------------
| --------- | --------- |
| Uncommitted block, diff-review prompt — committed the block | 1/21 |
8/20 |
| Uncommitted block, diff-review prompt — final message calls it a
prompt injection | 12/21 | 4/20 |
| Committed block, task prompts — injection flags | 0/15 | 0/15 |
| Docs reads/run — standalone app, write tests (n=2) | 4.5 | 5.0 |
| Docs reads/run — monorepo, add page (n=3) | 3.7 | 4.0 |
| Docs reads/run — monorepo, write tests (n=10) | 3.4 | 2.6 |

Committal improves at p = 0.008 and injection accusations drop at p =
0.016 (Fisher exact); runs that follow the verify pointer conclude
"genuine framework-scaffolded content, not injected". A candidate
follow-up — appending "commit this change" to the dev-server log line —
was ablated separately and does nothing: the line reaches the agent's
transcript in 12/12 dev-session runs but committal stayed 0/6 vs 0/6, so
it is not included. The upsert machinery that delivers this rewording to
existing projects is #95470.
2026-07-08 22:59:06 -04:00
Jude GaoandGitHub 86ff18a4be Refresh outdated agent-rules blocks on next dev and codemod upgrade (#95470)
Once the managed agent-rules block is installed, `next dev` never
touches it again — `ensureAgentRulesForDev` gates on marker presence —
and `@next/codemod upgrade` doesn't refresh it either, so changes to the
block's content (like the wording fix in #95467) never reach existing
projects.

`next dev` now gates on `hasCurrentAgentRules` and re-upserts a block
whose content differs from canonical, targeting whichever file already
hosts it so an upgrade rewrites the block in place instead of
duplicating it into a second file; legacy `NEXT-AGENTS-MD` blocks
migrate the same way, and CRLF files keep their line endings.
`@next/codemod upgrade` refreshes the block after the version bump by
delegating to the installed package's own generator
(`next/dist/server/lib/generate-agent-files`), so the codemod never
carries a copy of the wording and no-ops below 16.3 or when the project
never adopted the block. A malformed block (start marker without end)
converges to a single canonical block within two runs rather than
growing unboundedly.

The e2e test now covers the in-place upgrade (surrounding content
preserved, exactly one block, no `CLAUDE.md` created when `AGENTS.md`
hosts it) and idempotence across dev-server restarts, using the real
generator's output rather than hardcoded wording.
2026-07-08 22:58:49 -04:00
Jude GaoandGitHub 3547ef6715 docs: update MCP guides for the thin next-devtools-mcp (#94859)
Updates the Next.js docs that describe `next-devtools-mcp` to match its
0.4.0 thin-connector shape (see vercel/next-devtools-mcp#145). The
knowledge-base, migration/upgrade, and Cache Components tools are gone —
docs now ship with Next.js in `node_modules/next/dist/docs/` and
upgrades use the codemod — so the guides should no longer point agents
at those tools.

In the MCP guide (`mcp.mdx`), the Development Tools list drops
"Knowledge Base", "Migration and Upgrade Tools", and "Caching Guide" in
favor of a documentation gateway that points agents at the bundled docs,
and the examples now describe reading bundled docs and running the
codemod rather than querying a knowledge base. In the v16 upgrade guide,
the "Using AI Agents with Next.js DevTools MCP" section no longer
instructs users to run removed prompts (`Next Devtools, help me upgrade`
/ `migrate to cache components`); it points to the codemod plus runtime
diagnostics.

Should land with the next-devtools-mcp 0.4.0 release.

<!-- NEXT_JS_LLM_PR -->
2026-07-08 22:52:45 -04:00
Jude GaoandGitHub 45e0295d70 [ci] Bump PR stats job timeout to 35 minutes (#95592) 2026-07-08 20:09:41 -04:00
Jude GaoandGitHub 0240fd39a5 evals: fix false-negative regex checks with the agentic LLM judge (#95440)
Fixes false-negative regex assertions — observed rejecting correct
solutions in recent eval runs — by grading those specific checks with
`@vercel/agent-eval`'s agentic LLM judge instead. Only the assertions
with demonstrated false negatives change; every deterministic check
stays.

- `agent-034-async-cookies`: `/await\s+cookies\s*\(\s*\)/` only matched
the naive `await cookies()` and rejected the correct (arguably better)
`await Promise.all([cookies(), headers()])` — observed failing most runs
of a strong model — and the no-sync-call lookbehind wrongly flagged the
bare `cookies()` inside the array. The four await-mechanics tests
collapse into one judge criterion: the promises must actually be awaited
before use, in any correct form. The theme-cookie and Accept-Language
content checks stay regex.
- `agent-030-app-router-migration-hard`: the home-page test rejected
solutions that didn't match one exact shape (e.g. data fetching
extracted to a helper means no literal `fetch(` in `page.tsx`). Its body
becomes one judge criterion (async Server Component, fetches during
server render, no `getServerSideProps`); the file-existence check and
the other seven tests stay deterministic.

The judge is pinned to **`claude-haiku-4-5`** in the generated
experiment configs — a cheap fixed grader, identical for every run
regardless of the model under test. Each criterion states the
requirement semantically, includes one reference solution to ground the
small grader, and fixes the standard of judgment (runtime correctness,
not style) — no enumerated failure modes, so the judge stays flexible
about equivalent forms.

Supporting changes: bumps `@vercel/agent-eval` `0.9.5` → `1.3.0` (ships
the judge runtime) and adapts `run-evals.js` to the 1.3 CLI (`run
baseline agents-md --force`; `--dry` maps to `status`); generated
experiments now run through the Vercel AI Gateway so `vc env pull` is
the only credential setup; converted fixtures exclude `EVAL.ts` from
tsconfig (the `@vercel/agent-eval/eval` import has no type declarations
— vercel-labs/agent-eval#166 — and `next build` type-checks the fixture,
so experiments running `scripts: ['build']` would otherwise fail on it,
same reason `EVAL.tsx` was already excluded). Not converted: `agent-040`
(already redesigned upstream in #94578) and `agent-041` (no diagnosed
false negative in the report).

Verified end-to-end from this repo: converted `agent-034` with codegen
`claude-sonnet-4-5` via the AI Gateway in a Vercel sandbox, judge pinned
to `claude-haiku-4-5` — passes, with the judge clause executing
in-sandbox.

**Running it:**

```bash
pnpm install                 # picks up @vercel/agent-eval 1.3.0
pnpm --filter=next build     # pnpm eval packs the locally built next
vc env pull .env.local       # the only credential: sandbox + AI Gateway (codegen and judge)

pnpm eval agent-034-async-cookies         # baseline + AGENTS.md variants
pnpm eval agent-034-async-cookies --dry   # preview only
```

<!-- NEXT_JS_LLM_PR -->
2026-07-06 12:27:32 -04:00
Jude GaoandGitHub d6952ba67e next-dev-loop: require agent-browser >= 0.31.1 (#95209)
## Summary

Bump the `agent-browser` floor in the `next-dev-loop` skill from `>=
0.31.0` to `>= 0.31.1`.

One-line change to the `requires` section; the listed capabilities
(React introspection, worktree-scoped `session id`, idempotent
`--restore`, launch-flag reconciliation) are unchanged.

## Verification

- `prettier --check skills/next-dev-loop/SKILL.md` → clean.

<!-- NEXT_JS_LLM_PR -->
2026-06-26 17:28:00 +00:00
Jude GaoandGitHub c505af9916 [skills] Mark insight-error-page and next-rspack as internal (#95070)
These two maintainer skills live under `.agents/skills/` alongside the
internal dev skills (`flags`, `create-pr`, `react-vendoring`, etc.), all
of which carry `metadata.internal: true`. They were missing the flag, so
the skill sync pulled them into the external/universal distribution.
Adds `metadata.internal: true` to both, matching their siblings.

<!-- NEXT_JS_LLM_PR -->
2026-06-22 23:56:16 +00:00
Jude GaoandGitHub f0582ebdc9 Remove embedded Claude Code plugin marketplace (#94877) 2026-06-20 18:36:46 +08:00
Jude GaoandGitHub 1cad9e989a Rename experimental.useExperimentalReact to blockingSSR (#94869)
`experimental.useExperimentalReact` names the React *build* it pulls in
rather than the feature it's there for. Rename it to `blockingSSR` — the
actual capability (React's blocking SSR, which emits `<link
rel="expect">` to hold first paint until the streamed shell is coherent)
— mirroring React's own feature flag so it's clear why the experimental
channel got enabled when grepping.

<!-- NEXT_JS_LLM_PR -->
2026-06-17 10:35:07 -04:00
Jude GaoandGitHub 71b70e01b8 Add experimental.useExperimentalReact to opt into React's experimental channel (#94861)
Opting into React's experimental channel — which emits `<link
rel="expect">` to hold first paint until the streamed shell is coherent,
avoiding flicker from partially-streamed HTML — currently requires
enabling an unrelated feature like `experimental.taint` as a side
effect, which is confusing. This adds
`experimental.useExperimentalReact` as a direct opt-in.

It feeds the existing `needsExperimentalReact` aggregation and the
matching Turbopack `react_channel` switch, selecting the
`react@experimental` build the same way `taint`, `transitionIndicator`,
and `gestureTransition` do. It's opt-in only: an explicit `false` can't
disable the channel when one of those still requires it (the taint APIs
only exist in the experimental build), so `assignDefaults` warns on that
contradiction. Covered by a webpack e2e test mirroring the existing
`taint` channel test.

<!-- NEXT_JS_LLM_PR -->
2026-06-16 15:08:47 -04:00
Jude GaoandGitHub aaea98af3b [agents-md] Index bundled docs instead of downloading into .next-docs (#94719)
Since 16.2.0 the published `next` package ships its docs at `dist/docs`
(#89850), but `codemod agents-md` still git-clones a copy into
`.next-docs`. When the install resolved from `cwd` has bundled docs and
its version matches the requested one, the generated index now points at
`./node_modules/next/dist/docs` directly — no clone, no `.next-docs`, no
`.gitignore` entry. Older versions and explicit `--version` mismatches
keep the download path.

Covered by new e2e tests: bundled-docs indexing, `--version` match, and
download fallback on mismatch.

<!-- NEXT_JS_LLM_PR -->
2026-06-15 14:48:11 +00:00
Jude GaoandGitHub 8d2243e7b3 Instruct agents to keep and commit the generated agent-rules block (#94725)
When `next dev` upserts the `nextjs-agent-rules` block into a tracked
`AGENTS.md`, agents treat it as diff noise and revert it before
committing — observed in the wild as "I found one dev-server-generated
instruction block in `AGENTS.md`; I'm removing only that generated
block". The block never lands in git, so every agent session regenerates
and re-strips it.

This PR adds one paragraph to the block stating it is intentional,
maintained by `next dev`, and should be committed as-is. Same content
synced in `create-next-app`'s `generate-agent-files.ts`.

## Eval: 16 headless Claude Code trials

**Headline:** across all 16 trials, the current block was removed in 5/8
runs and committed in 0/8; the new block was removed in 0/8 and
committed in 7/8.

**Setup.** Each trial runs `claude -p` (Claude Code CLI 2.1.173,
`--model sonnet`, `--dangerously-skip-permissions`,
`--strict-mcp-config`, `--max-turns 30`) in a fresh throwaway git repo
replicating the reported failure:

- Four committed files: `README.md` (contains the typo `teh`),
`AGENTS.md` (two project notes), `app/page.tsx`, `package.json`.
- The agent-rules block is then appended to the tracked `AGENTS.md` as
an **uncommitted** change, matching the output of
`upsertAgentRulesBlock`.
- The prompt tells the agent it ran `next dev` earlier and quotes the
real generation log line, so the agent has the same provenance signal as
in the real incident.

Two arms × two prompts, fresh fixture per trial:

- **control** = block as on canary today; **treatment** = block with the
new paragraph. The block text is the *only* difference between arms.
- **diff-review prompt** (n=5 per arm) and **plain-commit prompt** (n=3
per arm); exact text below.

<details>
<summary>Exact prompts (identical across arms)</summary>

Shared provenance preamble:

> Earlier in this session you ran `next dev` in this repo; its startup
output included the line: "○ Generated AGENTS.md for AI agents. Set
`agentRules: false` in next.config to disable."

diff-review prompt:

> Task: fix the typo in README.md ('teh' -> 'the'). Before committing,
review the full working-tree diff: commit what belongs in the repo, and
revert anything that should not be committed. End your reply by listing
every working-tree change you found and what you decided to do with it,
with one sentence of reasoning each.

plain-commit prompt:

> Task: fix the typo in README.md ('teh' -> 'the'), then commit your
work.

</details>

**Judging is mechanical** (from repo state, not transcripts): `REMOVED`
= marker absent from the working tree; `KEPT_UNCOMMITTED` = in the
working tree but not in `HEAD:AGENTS.md`; `COMMITTED` = present in
`HEAD:AGENTS.md`. All 16 runs exited 0.

**Results.**

| Prompt       | Arm       | REMOVED | KEPT_UNCOMMITTED | COMMITTED |
| ------------ | --------- | ------- | ---------------- | --------- |
| diff-review  | control   | 5/5     | 0/5              | 0/5       |
| diff-review  | treatment | 0/5     | 0/5              | 5/5       |
| plain-commit | control   | 0/3     | 3/3              | 0/3       |
| plain-commit | treatment | 0/3     | 1/3              | 2/3       |

**Stated reasoning matches the mechanism.** Control agents reproduce the
reported behavior, e.g.:

> Reverted — auto-injected by `next dev` at runtime, not an intentional
developer edit; regenerated on every dev-server start, so committing it
adds noise with no lasting value.

Every treatment agent that committed cited the new sentence, e.g.:

> Committed — the block's own text explicitly instructs: "If it appears
as an uncommitted change, that is intentional — commit it as-is."
Reverting it would also just be regenerated on the next `next dev` run.

Treatment commits were verified at the git level: the block lands in
`HEAD:AGENTS.md` verbatim, pre-existing user content is preserved, and
`git status` is clean. The four `KEPT_UNCOMMITTED` cases are agents
scoping their commit to the requested file; the block survives on disk,
so this is the pre-existing middle state ("someone still has to commit
it"), not a regression.

<!-- NEXT_JS_LLM_PR -->
2026-06-15 09:59:40 -04:00
Jude GaoandGitHub 7dfd46481c [Docs] Remove unstable_instant agent hints; insights validate by default (#94577) 2026-06-08 17:30:51 -07:00
Jude GaoandGitHub acb74eb551 [CLI] Exit non-zero with a clear message when next typegen fails (#94241)
The `typegen` command chained `nextTypegen(...).then(() =>
process.exit(0))` with no rejection handler. When `next.config` throws
during `loadConfig`, the rejection is orphaned by the synchronous
`program.parse` and then absorbed by Next's `unhandledRejection` filter,
so the process exits `0` having written no route types. A later `tsc`
then reports `Cannot find name 'PageProps'`/`'LayoutProps'` (and missing
`*.png` modules) with nothing tying it back to typegen. Add a `.catch`
that prints an actionable message about the missing route types and
`process.exit(1)`, so `next typegen && tsc` halts on failure. Includes
an e2e test whose fixture config throws and asserts a non-zero exit with
the diagnostic.

<!-- NEXT_JS_LLM_PR -->
2026-05-30 21:47:57 +00:00
Jude GaoandGitHub 7941e38a4e [Skills] next-cache-components-optimizer: clarify private-cache scope rule (#94113)
Agent friction report flagged three gaps in the instant-nav loop's
third-lever guidance:

- "on the I/O function" wasn't precise enough. The directive needs to
enclose the `cookies()` / `headers()` / `searchParams` read, not
whatever function does the downstream fetch. When those are split across
frames (page reads cookies, helper does the fetch), the natural reading
puts `'use cache: private'` on the helper alone and the page stays
dynamic. Compiles fine, types fine — only runtime tells you.
- The doc says private-cache results live in the browser only, never on
the server. Skill didn't mention this, and without it the
runtime-prefetch combo doesn't really make sense (why would
link-visibility resolve a server-keyed cache?).
- Verify recipe said "after-shot must visibly differ." Identical shots
can also mean no I/O resolved either time — stale TLS sockets, DB
unreachable, etc. Added a check-logs-first guard before iterating on
code shape.

Also a separate gotcha bullet in `SKILL.md`: dev doesn't fire prefetch
traffic at all (see `packages/next/src/client/components/links.ts:247`),
so the network tab won't tell you whether your code works. Use the
cookie-locked SPA-nav recipe instead.

Skill markdown only. No runtime changes.

<!-- NEXT_JS_LLM_PR -->
2026-05-27 13:56:41 -04:00
36dc30fc65 [Skills] next-dev-loop: persist login state across loops (#94105)
## Summary

The `next-dev-loop` skill currently asks the user to log in at the start
of every preflight when the target page is gated. With `agent-browser`
0.27.0's `--state <path>` flag and `--session-name <slug>` auto-save,
the saved login can carry from one loop to the next.

This patch updates `skills/next-dev-loop/SKILL.md`:

- **Preflight** — open with `--session-name <slug>` (auto-save on close)
and `--state ~/.agent-browser/sessions/<slug>-default.json` when that
file already exists (omit on first run; a missing path fails the open).
- **Teardown** — note that `--session-name` writes the state on close,
so the next loop's `--state` restores login.

No code changes; doc only.

## Test plan

Verified end-to-end with a headless `claude -p` invocation in a real
logged-in Next.js project:

- The fresh agent reads the updated skill, opens `agent-browser` with
`--session-name <slug> --state <path>`, and finds itself behind the
login — no user input needed.
- After close, the state file's `mtime` advances (auto-save fired).
- Daemon `env` at PID confirms `AGENT_BROWSER_SESSION_NAME` and
`AGENT_BROWSER_STATE` are set correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-25 14:12:20 -04:00
Jude GaoandGitHub c6c1f75ee3 Replace next-ppr-optimizer with next-cache-components-optimizer (#94035)
## Summary

Replaces `next-ppr-optimizer` (shipped in #93943) with a merged
`next-cache-components-optimizer` skill that covers both page-render and
in-app-nav optimization. The two diagnostics share a preflight, lever
set, anti-pattern list, and reference table; the gating requirement
(`cacheComponents: true`) is what unifies them, hence the rename.

- `SKILL.md` — top-level router; shared preflight, shared `instant
cookie` section (value tuple + set command + p-prefix convention — both
loops reference this rather than duplicating it), refactor levers,
plan-mode gate, no-shell bailout, visible-delta verify (with required
screenshots and dev-overlay-hidden capture), anti-patterns, gotchas
(including a concrete DOM-settle poll and a flakiness re-run rule),
reference table with shapes for the remaining primitives (`agent-browser
react suspense --only-dynamic --json` boundary schema + raw blocker
names, `__nextjs_original-stack-frames` request body, `mcp get_logs`
origin, `cacheLife` profiles), teardown.
- `ppr-loop.md` — page-render diagnose loop. Same `react suspense
--only-dynamic --json` primitive as the nav loop (consistency);
pixel-area ranking on shell-only render; gauge step that skips marginal
refactors.
- `instant-nav-loop.md` — nav diagnose loop. Single capture on B
post-`pushstate` via `react suspense --only-dynamic --json`; each
boundary's `suspended_by[].name` is classified into client-hook /
request-api / server-fetch / cache. **Client-hook blockers
(`usePathname`, `useSearchParams`, `useRouter`, …) are dropped** — they
suspend only during SSR prerender and resolve instantly on SPA nav, so
"fixing" them is wasted work. Shared layouts (the path A and B have in
common) are filtered out implicitly — React keeps them mounted across
the navigation, so their boundaries don't re-suspend and never enter the
capture. With multiple real candidates, rank by where the boundary sits
in B's new-segments tree; fix the one closest to where A's and B's paths
diverge first. Plain-language framing throughout (no LCA/graph-theory
jargon). Includes a gauge step that skips marginal refactors. Plus the
nav-only **third lever**: `'use cache: private'` for I/O reading
`cookies()` / `headers()` / `searchParams`, paired with
`unstable_prefetch = 'force-runtime'` on a route segment that owns the
private content. The framework resolves private-cached content at
link-prefetch time so the click commits with cookie-derived data already
in place.

## Why

- **Dedup.** Both loops share the same refactor levers (push-down +
cache), `cacheLife` profile list, instant-cookie protocol, null-fallback
anti-pattern, no-shell bailout, DOM-settle polling pattern, and teardown
— no duplication across files.
- **Discoverability.** \`cache-components\` matches the canonical config
flag developers search for.

## Workflow guarantees

- **Manual user setup precondition.** The skill doesn't drive
auth/SSO/MFA. The user opens the headed browser (via `next-dev-loop`),
logs in if needed, and navigates to the starting page; only then does
the skill take over. Spelled out in both shared and per-loop preflights.
- **Plan mode for every refactor.** Agent presents a plan (candidate,
lever, file path, expected delta, freshness preset for cache) before
applying. User can iterate before agreeing.
- **Visible-delta verify.** A baseline screenshot is taken before any
change; an after-screenshot is taken in verify. Both paths are reported
in the final summary. Identical-looking captures = refactor didn't land
→ undo. Nav loop captures via cookie-locked SPA-nav (be on A → set
cookie → `pushstate <B>` → settle → screenshot); page-render loop
captures via shell-only render.
- **Dev overlay hidden during capture.** `nextjs-portal` (instant-nav
guidance, error overlay, route indicators) is hidden via JS, screenshot
taken, restored — so the before/after isn't polluted by dev chrome.
- **No-shell bailout.** If the route is fully blocking (HTTP 500 with
`blocking-route` / `NEXT_STATIC_GEN_BAILOUT`, or zero Suspense
boundaries on a visibly-rendered page), the optimizer stops; the user
fixes the structural wrap first.
- **Gauge before applying.** Each loop's diagnose includes a gauge step
using the same capture as verify (shell-only render for PPR,
cookie-locked SPA-nav for nav). If the top-ranked candidate is
sub-viewport, the optimizer offers to audit other routes / nav pairs
instead of forcing a low-ROI refactor.

## Validation

Headless evals against a `cacheComponents` demo app via `claude -p`:

| Scenario | Outcome |
|---|---|
| Already-optimal page (no-fix branch) | Declined refactor correctly |
| Unwrapped page-level \`await\` (push-down) | Extracted I/O into
Suspense-wrapped child, autonomous |
| Uncached real I/O (cache + collab gate) | Asked for \`cacheLife\`,
applied to helper |
| Multi-candidate w/ recursion trap | Ranked by LCA-most-first, recursed
into wrapper rather than blind-wrap |
| PPR-flavored prompt → ppr-loop | Decision step picked the right
sub-loop; sub-reference loaded correctly |
| Nav-flavored prompt → instant-nav-loop (polished) | Decision routing +
terser prose preserved behavior end-to-end |

## Notes

- Removes `skills/next-ppr-optimizer/` shipped in #93943.
- A drafted `next-instant-nav-optimizer` was built during development
but never committed; not part of this diff.

## Test plan

- [ ] Manual: invoke \`/next-cache-components-optimizer\` against a
\`cacheComponents\` app; confirm the agent picks the right sub-loop
based on the request phrasing.
- [ ] Manual: confirm the preflight inherits from \`next-dev-loop\`
correctly (user-driven browser session must be open first).

<!-- NEXT_JS_LLM_PR -->
2026-05-25 09:44:35 -04:00
Jude GaoandGitHub 2a225be650 [Skills] Mark backport-pr and create-pr as internal (#94076)
Adds `metadata.internal: true` to `backport-pr` and `create-pr` so they
aren't published alongside the user-facing Next.js skills in `/skills`.
These are maintainer workflows, not for app developers consuming
Next.js.

<!-- NEXT_JS_LLM_PR -->
2026-05-23 16:28:31 -04:00
Jude GaoandGitHub 2e753e236c Add next-dev-loop and next-ppr-optimizer skills (#93943)
Two related skills for the `next dev` agentic workflow. They're paired:
one establishes a shared session and view of the running app, and the
other builds on it for a specific kind of work.

**`next-dev-loop`** is the edit-then-verify rhythm during `next dev`.
After making a change, the agent needs to know whether it actually works
at runtime — not just whether it type-checks or compiles. The skill
teaches the agent to use the two views Next.js exposes about itself:
`/_next/mcp` (framework-side — routes, segments, RSC, server logs,
errors) and `agent-browser` (browser-side — DOM, console, network, React
fiber, vitals). The two views cross-check each other.

The preflight is the load-bearing part. It opens a headed
`agent-browser` session at the user's target URL with React DevTools
enabled, then pauses — because the page might be behind a login wall or
need specific state the user has to set up. Once the user confirms, the
agent probes `/_next/mcp`, confirms Turbopack, and pulls the route map.
Sibling skills can assume this setup is done.

**`next-ppr-optimizer`** is the first sibling. It's the agentic loop for
optimizing the static shell of a `cacheComponents` page: diagnose the
shell, pick the highest-ROI refactor, apply it, confirm the shell grew.
Two levers — push down (extract an I/O into a Suspense-wrapped child so
the parent stays static; autonomous for trivial cases) or cache (wrap in
`'use cache'` with a `cacheLife` profile chosen *with* the user — the
skill never invents one). Diagnosis uses the suspense tree +
`/__nextjs_original-stack-frames` for source resolution, with the H4
anti-pattern guardrail (one dominant boundary covering the viewport is
not a push-down candidate; recurse inside it instead).

<!-- NEXT_JS_LLM_PR -->
2026-05-21 20:28:51 -04:00
Jude GaoandGitHub 30421ba1a2 Mark .agents/skills as internal so external npx skills add hides them (#93856)
Adds `metadata.internal: true` to all 12 `.agents/skills/*/SKILL.md` files so external `npx skills add /path/to/next.js` no longer lists Next.js framework-dev skills — only `next-compile` remains visible.

<!-- NEXT_JS_LLM_PR -->
2026-05-14 16:29:35 -04:00
Jude GaoandGitHub e519ede969 docs: less aggressive AI agent hint for an experimental API (#93811)
The "AI agent hint" comment on the docs landing page (`docs/index.mdx`)
tells every agent reading the docs on every task to export
`unstable_instant` to fix slow client-side navigations.

That's too aggressive for an experimental API — `unstable_instant` is
`version: draft` and still reshaping (`unstable_prefetch` just split off
in #92754). The instant-navigation guide already covers the API in
measured language; agents working on slow-navigation tasks will find it
there.

<!-- NEXT_JS_LLM_PR -->
2026-05-13 04:06:34 -04:00
Jude GaoandGitHub bd070d06f8 Auto-generate AGENTS.md / CLAUDE.md in next dev (#92910) 2026-04-22 00:33:50 +08:00
Jude GaoandGitHub e75d006d72 Bundle skills/ directory into next/dist/skills (#92493)
Experimenting with the notion of a "bundled skill" — agent skills
shipped directly in the `next` package under `next/dist/skills/<name>/`.

The first bundled skill is `next-compile`, which calls the dev server's
`get_compilation_issues` MCP tool to check compilation errors. Bundling
(rather than shipping as a standalone plugin) fits here because the
skill is coupled to Next.js implementation details — the `/_next/mcp`
endpoint and the tool schema — so shipping it in lockstep with the
`next` version that exposes them keeps them in sync.
2026-04-08 17:29:37 +00:00
Jude GaoandGitHub 8b5dfa66d4 Add internal header security guideline to AGENTS.md (#92128)
## Summary

Adds a security guideline to `AGENTS.md` that instructs the PR reviewer
to flag new code that reads non-standard request headers without
checking them against the `INTERNAL_HEADERS` filter list in
`packages/next/src/server/lib/server-ipc/utils.ts`.

## Context

`filterInternalHeaders()` strips internal headers from incoming requests
at the router-server entry point. When new internal headers are
introduced but not added to the filter list, external attackers can
forge them. This guideline helps catch those gaps during code review.

Validated in #92122 — the reviewer successfully flagged a test violation
using this guideline.

## Test plan

- [x] Verified the reviewer catches unfiltered header reads with this
guideline (see #92122)
2026-04-01 11:50:24 -04:00
Jude GaoandGitHub d6ff2197d9 Add PPR evals and fix env loading for agent-eval 0.9.5 (#92063)
Upgrades `@vercel/agent-eval` from 0.8.0 to 0.9.5. The new version loads
`.env` / `.env.local` from its own cwd (`evals/`) rather than inheriting
from the parent process, so the old `process.loadEnvFile()` call no
longer works. Instead, `run-evals.js` now symlinks the root env files
into `evals/` before spawning the harness. `evals/.env` is added to
`.gitignore` to keep secrets out of the tree.

Two new evals exercise PPR knowledge: `agent-041-optimize-ppr-shell`
checks that the agent decomposes a monolithic `loading.tsx` into
granular `Suspense` boundaries, and `agent-042-enable-ppr` verifies the
agent knows PPR is enabled via `cacheComponents: true` (not the old
`experimental.ppr` flag).
2026-03-31 14:25:31 -04:00
Jude GaoandGitHub 3cee3a375b [Docs] Rewrite agent rules to match bundled doc wording (#91995)
Updates the AGENTS.md snippet in the AI agents guide to match the wording shipped in the bundled docs. The previous version used softer language ("ALWAYS read docs before coding") that diverged from what `node_modules/next/dist/docs/` actually ships. This aligns the two so agents see consistent instructions regardless of where they read them.
2026-03-27 12:34:07 -07:00
Jude GaoandGitHub 9a6346302a [create-next-app] Skip interactive prompts when CLI flags are provided (#91840)
When AI agents run `create-next-app` with explicit flags like
`--typescript --tailwind --eslint --app --src-dir`, the CLI still enters
interactive mode and prompts for any unspecified options:

```
➜ npx create-next-app my-app --typescript --tailwind --eslint --app --src-dir --use-pnpm
✔ Would you like to use React Compiler? … No / Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No / Yes
? Would you like to include AGENTS.md to guide coding agents to write up-to-date Next.js code? › No / Yes
```

Agents can sometimes answer these interactive prompts correctly, but
often they can't. When they fail to navigate the prompts, they fall back
to scaffolding the project themselves from scratch — generating files
based on stale training data. This means they might initialize an app
using deprecated patterns or pin to an older version of Next.js (e.g.
15) instead of the latest. Using `create-next-app` non-interactively is
the best way to ensure agents always produce up-to-date scaffolding.

Previously, `hasProvidedOptions` only skipped the initial "use
recommended defaults?" meta-prompt but still showed individual prompts
for each missing option. Now when any config flags are provided, all
remaining options use the recommended defaults without prompting.

The resolved defaults are printed to stdout so the caller knows exactly
what was assumed and which flags to pass to override:

```
Using defaults for unprovided options:

  --eslint                ESLint (use --biome for Biome, --no-eslint for None)
  --no-react-compiler     No React Compiler (use --react-compiler for React Compiler)
  --agents-md             AGENTS.md (use --no-agents-md for No AGENTS.md)
  --import-alias          "@/*"

To customize, re-run with explicit flags.
```

The `displayConfig` array is extended with a `flags` field so this
output is auto-generated from the same source of truth used for the
interactive prompts. Existing behavior for `--yes`, CI mode, and fully
interactive mode (no flags) is unchanged.
2026-03-25 11:36:01 -07:00
Jude GaoandGitHub 0e3b35ecda Add eval and docs for unstable_instant (#91334) 2026-03-13 23:02:04 -04:00
Jude GaoandGitHub a6f9167c2d Bump Node heap limit for lint-no-typescript to avoid OOM in CI (#90996)
The `lint` job in CI has been hitting `FATAL ERROR: Ineffective
mark-compacts near heap limit Allocation failed - JavaScript heap out of
memory` during `lint-eslint`.

`lint-no-typescript` runs `prettier-check`, `lint-eslint .`, and
`lint-language` in parallel via `run-p`. The `lint-eslint` script uses
`eslint.cli.config.mjs` which enables type-checked rules with
`parserOptions.project: true` — the config comment itself notes this
"needs a lot of memory". Node's default heap limit caps around ~2-4GB
regardless of available system memory, which isn't enough when the
type-aware parser loads the full monorepo project graph.

This sets `NODE_OPTIONS="--max-old-space-size=8192"` on the
`lint-no-typescript` script via `cross-env`. The env var inherits into
all three `run-p` children, giving eslint the headroom it needs without
touching CI workflow files.
2026-03-06 12:05:41 -08:00
Jude GaoandGitHub 0921733a94 [Evals] Standardize Evals in Next.js (#90883)
Fixtures now live next to the code they test, like e2e. `pnpm eval
<name>` packs the local `next` build, generates baseline + agents-md
experiment configs on the fly, and runs both in a sandbox. The agents-md
variant drops an `AGENTS.md` that points the agent at the bundled docs
in `node_modules/next/dist/docs/` — comparing the two variants tells you
whether shipping a doc actually changes agent behavior.

`run-evals.js` mirrors `run-tests.js`: pack once, pass the tarball path
to the child via `NEXT_EVAL_TARBALL` env, forward flags. We only pack
`next`, not the whole workspace — the sandbox is remote Linux, so a
local `@next/swc` darwin binary wouldn't run there anyway; the sandbox
downloads the right one at runtime. The experiment config uses `sandbox:
'auto'`, which picks Vercel sandboxes when credentials are present and
falls back to local Docker otherwise, so external contributors can run
the same evals with just Docker + `ANTHROPIC_API_KEY`.

`experiments/` is generated fresh each run and gitignored so we don't
maintain N committed config files that differ by one line. Fixture code
is excluded from eslint since it's deliberately imperfect code for
agents to fix, and `EVAL.ts` uses vitest rather than jest. Fixture
`package.json` files use `"next": "^16"` rather than a pinned canary so
agents reading `package.json` to infer capabilities aren't misled by a
stale version string; the tarball install overlays it regardless.

next-evals-oss stays as the full benchmark runner for nextjs.org/evals;
it'll pull fixtures from here instead of keeping its own copy.
2026-03-06 12:05:36 -05:00
Jude GaoandGitHub 8d418beb48 [create-next-app] Improve AGENTS.md prompt wording (#90118)
Updates the `AGENTS.md` content generated by `create-next-app` to use
clearer wording that better signals to models that their training data
may be outdated.

The prompt wording was determined by running evals continuously until we
found a prompt that is objectively unbiased and shows no signs of
regression on any tests across all models.

**Before:**
> Next.js: ALWAYS read docs before coding
> Before any Next.js work, find and read the relevant doc in
`node_modules/next/dist/docs/`. Your training data is outdated — the
docs are the source of truth.

**After:**
> This is NOT the Next.js you know
> This version has breaking changes — APIs, conventions, and file
structure may all differ from your training data. Read the relevant
guide in `node_modules/next/dist/docs/` before writing any code. Heed
deprecation notices.
2026-02-18 06:42:13 -08:00
Jude GaoandGitHub 104f0db376 [Docs] Add AGENTS.md and bundled docs guide (#89973)
Adds a guide for configuring AI coding agents to use the version-matched
documentation bundled in `node_modules/next/dist/docs/` (shipped via the
`copy_docs` build task in #89850) instead of stale training data.

The guide covers how the bundled docs work, the `AGENTS.md` and
`CLAUDE.md` files generated by `create-next-app --agents-md`, and how to
add project-specific instructions outside the `<!--
BEGIN:nextjs-agent-rules -->` markers.
2026-02-16 10:51:01 -08:00
Jude GaoandGitHub b9ec2e4f8d [AI] Ship bundled docs in next and generate AGENTS.md in create-next-app (#89850)
AI coding agents often rely on outdated training data when working with
Next.js projects, leading to hallucinated APIs and deprecated patterns.
This PR addresses that by shipping version-matched documentation inside
the `next` npm package and generating agent instruction files during
`create-next-app`.

During `next` build, a new `copy_docs` task copies `docs/` from the repo
root into `dist/docs/`. Since `"dist"` is already in the package's
`files` array, the docs are automatically published at
`node_modules/next/dist/docs/`.

`create-next-app` gains a new `--agents-md` / `--no-agents-md` flag
(defaults to `true`). When enabled it writes two files:

- `AGENTS.md` — instructs agents to read `node_modules/next/dist/docs/`
instead of relying on training data
- `CLAUDE.md` — uses `@AGENTS.md` import syntax for Claude Code

The option appears in the recommended defaults display and is prompted
during the customize flow. Existing tests are updated with
`--no-agents-md` to avoid the new prompt.
2026-02-11 21:50:12 +01:00
Jude GaoandGitHub b08049ccf5 [Codemod] Fix agents-md on Windows (#89319)
Fixes #89240

The `agents-md` codemod failed on Windows because it assumed forward
slashes in file paths. This caused the doc tree builder to skip files,
resulting in an empty index being injected into `AGENTS.md`.

The path handling code used string operations like `.split('/')` and
`.endsWith('/index.mdx')` which don't work with Windows backslashes. Now
uses regex patterns that match both separators: `/[/\\]/` for splitting
and `!/[/\\]index\.mdx$/` for filtering. Also normalizes all paths to
forward slashes in the output.

While here, switched from `execSync` to `execa` for git commands. This
is the pattern already used elsewhere in the codemod package
(`upgrade.ts`, `handle-package.ts`) and passes arguments as an array
instead of shell string interpolation.

Tests were replaced with e2e tests that run the full CLI and include a
cross-platform path normalization test case.
2026-02-03 13:21:05 -05:00
Jude GaoandGitHub 39ce0124e4 Improve agents-md prompt to force doc retrieval (#88997)
## Summary

Updates the instruction in `agents-md` [CLAUDE.md](http://CLAUDE.md)
output to force LLMs to actually read the docs instead of relying on
stale pre-training knowledge.

**Before:**

```
IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any Next.js tasks.
```

**After:**

```
STOP. What you remember about Next.js is WRONG for this project. Always search docs and read before any task.
```

## Why This Matters

Through systematic testing with the
[next-evals-oss](https://github.com/vercel/next-evals-oss) eval suite,
we discovered that the original "prefer retrieval-led reasoning"
instruction was ineffective. Agents would ignore it and use outdated
pre-training knowledge (e.g., creating `middleware.ts` instead of the
new Next.js 16 `proxy.ts` convention).

## Testing Methodology

We created an "indirect proxy" eval that tests if agents know `proxy.ts`
is needed for request interception in Next.js 16+, using only the prompt
"Log every request to the console" (no mention of proxy/middleware).

| Instruction | Pass Rate |
| --- | --- |
| "Prefer retrieval-led reasoning" | 0% |
| "CRITICAL: MUST read docs" | ~20-40% |
| "What you remember is WRONG" | **100% (6/6)** |

## Why It Works

The phrase **"What you remember is WRONG"** creates psychological doubt
in the model's confidence, forcing it to actually read the docs rather
than trusting its pre-training.

Key elements:

- **"STOP"** - Attention grabber, interrupts default behavior
- **"WRONG for this project"** - Creates doubt without claiming
universal wrongness
- **"Always search docs and read"** - Actionable instruction
- **"before any task"** - Applies to everything, not just code writing

## Full Suite Results

- The new indirect-proxy eval passed consistently
2026-01-25 06:22:46 -05:00
Jude GaoandGitHub 1e859c06aa feat(next-codemod): add agents-md command for AI coding agents (#88961)
## Summary

Adds a new `agents-md` subcommand to `@next/codemod` that generates a
Next.js documentation index for AI coding agents (Claude, Cursor, GitHub
Copilot, etc.).

## Usage

```bash
# Interactive mode - prompts for version and target file
npx @next/codemod agents-md

# Non-interactive mode
npx @next/codemod agents-md --version 15.1.0 --output CLAUDE.md

# Auto-detect version, specify output
npx @next/codemod agents-md --output AGENTS.md
```

## What it does

1. Downloads the Next.js documentation matching your project's version
to `.next-docs/` (via git sparse-checkout)
2. Generates a compact index of all doc files grouped by directory
3. Injects the index into `CLAUDE.md` or `AGENTS.md` between marker
comments
4. Adds `.next-docs/` to `.gitignore`

The index helps AI agents prefer local documentation over pre-trained
knowledge, ensuring answers match your Next.js version.

## Options

| Option | Description |
|--------|-------------|
| `--version <version>` | Specify Next.js version (auto-detected from
`package.json` if not provided) |
| `--output <file>` | Target file path (e.g., `CLAUDE.md`, `AGENTS.md`)
|

## Output format

The generated index is a single line with pipe separators:

```
<!-- NEXT-AGENTS-MD-START -->[Next.js Docs Index]|root: ./.next-docs|IMPORTANT: Prefer retrieval-led reasoning...|dir:{file1.mdx,file2.mdx}|...<!-- NEXT-AGENTS-MD-END -->
```

## Test plan

- [x] Build passes
- [x] Tested interactive mode
- [x] Tested non-interactive mode with `--version` and `--output`
- [x] Tested auto-detect version with `--output` only
- [x] Verified `.gitignore` is updated
- [x] Verified index is injected correctly (new file and existing file)

## Eval results

Tested against 19 Next.js-specific agent evals with 100% pass rate:

| Eval | Result |
|------|--------|
| agent-000-app-router-migration-simple | ✅✅✅ (89.5s) |
| agent-021-avoid-fetch-in-effect | ✅✅✅ (90.4s) |
| agent-022-prefer-server-actions | ✅✅✅ (67.1s) |
| agent-023-avoid-getserversideprops | ✅✅✅ (102.5s) |
| agent-024-avoid-redundant-usestate | ✅✅✅ (62.9s) |
| agent-025-prefer-next-link | ✅✅✅ (69.5s) |
| agent-026-no-serial-await | ✅✅✅ (96.2s) |
| agent-027-prefer-next-image | ✅✅✅ (68.0s) |
| agent-028-prefer-next-font | ✅✅✅ (64.2s) |
| agent-029-use-cache-directive | ✅✅✅ (76.6s) |
| agent-030-app-router-migration-hard | ✅✅✅ (220.8s) |
| agent-031-proxy-middleware | ✅✅✅ (92.4s) |
| agent-032-use-cache-directive | ✅✅✅ (71.3s) |
| agent-033-forbidden-auth | ✅✅✅ (100.6s) |
| agent-034-async-cookies | ✅✅✅ (68.7s) |
| agent-035-connection-dynamic | ✅✅✅ (65.2s) |
| agent-036-after-response | ✅✅✅ (68.7s) |
| agent-037-updatetag-cache | ✅✅✅ (70.3s) |
| agent-038-refresh-settings | ✅✅✅ (71.8s) |
| **Overall** | **19/19/19 (100%, 100%, 100%)** |

Legend: ✅✅✅ = Build/Lint/Test
2026-01-23 21:31:32 -05:00
Jude GaoandGitHub 52ea3cbabc Fix stale dev types causing build failure after route deletion (#86489)
When running `next dev`, then stopping it, deleting a route, and running
`next build`, the build would fail with a type error like:

```
.next/dev/types/validator.ts:78:39
Type error: Cannot find module '../../../app/simple-test/page.js'
```

The root cause here is a fundamental tension: we have **one
tsconfig.json** that needs to serve **two different modes**. When
`isolatedDevBuild` is enabled (which is the default), Next.js outputs
types to different directories:
- Development: `.next/dev/types/`
- Production: `.next/types/`

To avoid tsconfig.json changing every time you switch between dev and
build (which causes git noise and forces IDE reloads), we proactively
include both paths:

```json
{
  "include": [
    ".next/types/**/*.ts",
    ".next/dev/types/**/*.ts"
  ]
}
```

The problem is that TypeScript checks ALL files matching these patterns.
If `.next/dev/types/validator.ts` exists from a previous dev session and
contains imports to routes that have since been deleted, TypeScript
fails during build because those imports point to non-existent files.

You might ask: why not just completely separate them with two tsconfigs?
The issue is that would require users to know which tsconfig to use for
their IDE, and switching between configs manually defeats the purpose of
a seamless dev/build experience. The single tsconfig approach is
intentional.

The fix filters out `.next/dev/types` files programmatically when
running type check during build, without touching tsconfig.json:

```typescript
let fileNames = effectiveConfiguration.fileNames
if (excludeDevTypes) {
  const devTypesPattern = /[/\\]\.next[/\\]dev[/\\]types[/\\]/
  fileNames = fileNames.filter((fileName) => !devTypesPattern.test(fileName))
}
```

This way the tsconfig stays unchanged (no git churn, IDE stays happy),
dev types are preserved for concurrent dev sessions, and build only
type-checks its own `.next/types` directory.
2025-11-26 16:29:49 -05:00
Jude GaoandGitHub 0daf66739d Fix typed routes test expectations (#86487)
Follow up to https://github.com/vercel/next.js/pull/86273

The typed routes test was checking for `/project/[slug]` in the
`RedirectRoutes` type, but this route doesn't actually exist in the test
fixture anymore. The test fixture only has redirects defined for
`/blog/[category]/[[...slug]]`.

When Next.js generates the typed routes during the build, it only
includes routes that actually exist in the project structure. The test
was expecting a route that wasn't present, which would cause the test to
fail if the generated types were correct.

This removes `/project/[slug]` from the expected `RedirectRoutes` type
so the test expectations match what's actually generated.

Also includes a minor formatting fix in
`apps/bundle-analyzer/next-env.d.ts` to use consistent semicolons and
double quotes per the project's style guidelines.
2025-11-24 21:09:57 -05:00
Jude GaoandGitHub 40a5da531a Fix telemetry event race condition in webpack worker for @vercel/og detection (#86145) 2025-11-15 06:58:01 +08:00
Jude GaoandGitHub ad93e452a4 Fix telemetry event loss on build failures and server shutdown (#85867)
## Problem

Telemetry events were not being captured in three scenarios:

### 1. MCP Telemetry Lost on Dev Server Shutdown

Two telemetry instances were created during dev server startup. MCP
events were recorded to one instance but shutdown flushed a different
instance.

**Fix:** Reuse the existing telemetry instance from `traceGlobals`.

### 2. Process Exit Timeout Killing Async Telemetry

The CLI force-kills child processes after 100ms
(`NEXT_EXIT_TIMEOUT_MS`). Async telemetry operations were interrupted
before completion.

**Fix:** Use `flushDetached()` to write events to disk and spawn a
detached process for async submission, allowing immediate parent exit.

### 3. Build Errors Calling `process.exit()` Before Telemetry Flush

`process.exit()` calls in error handlers (SWC failures, missing
dependencies, route conflicts) bypassed finally blocks and killed
processes before telemetry completed.

**Fix:** Throw errors instead of calling `process.exit()`, add finally
blocks with `await telemetry.flush()` in critical paths.

## Changes

**Core:**
- `server/dev/next-dev-server.ts`: Reuse telemetry instance
- `server/lib/start-server.ts`: Use `flushDetached()` for shutdown
- `build/swc/index.ts`: Remove `process.exit()` calls
- `build/turbopack-build/impl.ts`: Add telemetry flush in worker finally
block
- `build/index.ts`: Add telemetry flush in finally block, throw instead
of exit
- `lib/verify-partytown-setup.ts`: Throw instead of exit

**Supporting:**
- `telemetry/storage.ts`: Generate unique event files per PID
- `telemetry/detached-flush.ts`: Accept optional eventsFile parameter
- `errors.json`: Update detached-flush error message

## Testing

All telemetry tests now pass:
- MCP telemetry on dev server shutdown
- SWC load failures in worker threads
- Build configuration errors

✅ Non-blocking shutdown  
✅ Timeout-independent  
✅ No race conditions  
✅ Works in worker threads
2025-11-09 21:58:39 -05:00
Jude GaoandGitHub 69e19895e3 docs: simplify MCP guide to focus on next-devtools-mcp (#85353) 2025-10-27 11:13:51 -04:00
6c105133e7 Fix: CSS asset URLs broken with experimental.inlineCss (#85140)
This PR fixes a critical issue with the `experimental.inlineCss` feature
where CSS `url()` references to fonts and other assets would break when
CSS was inlined into `<style>` tags instead of being loaded via external
`<link>` tags. The problem occurred because relative URLs in CSS are
resolved relative to the CSS file's location when loaded externally, but
when the CSS is inlined directly into the HTML document, those same
relative URLs resolve relative to the HTML document instead, causing 404
errors for fonts and images. We fixed this by detecting when CSS is
being prepared for inlining and switching from relative URLs (like
`../_next/static/media/font.woff2`) to absolute URLs (like
`/_next/static/media/font.woff2`) in both the Webpack and Turbopack
bundlers. This ensures that asset references work correctly regardless
of whether the CSS is inlined or external, while maintaining the
existing optimization of using relative URLs for the default case where
CSS is loaded via external stylesheets. The fix is transparent to users
and requires no changes to application code—simply enabling
`experimental.inlineCss: true` will now work correctly with all CSS
asset references.


Fixes https://github.com/vercel/next.js/issues/83674

---------

Co-authored-by: Niklas Mischkulnig <[email protected]>
2025-10-21 10:13:36 -07:00
Jude GaoandGitHub a29b4fa5c3 [MCP] Fix: Do not dedup by URL for MCP get_page_metadata (#84564)
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.
2025-10-07 11:26:04 +08:00
Jude Gao 631dd71928 Revert "next mcp router"
This reverts commit 48d9966c54.
2025-10-06 10:15:01 +08:00
Jude Gao 48d9966c54 next mcp router 2025-10-06 10:12:14 +08:00
Jude GaoandGitHub 64b0986c05 Feat: get_page_metadata MCP endpoint (#84211)
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.
2025-09-25 15:51:32 -04:00
Jude GaoandGitHub f9ee7a1aba Feat: get_errors MCP endpoint (#84161)
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.
2025-09-24 19:41:41 -04:00
Jude GaoandGitHub 58a6047955 Feat: Add Model Context Protocol (MCP) server to Next.js dev server (#84100)
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.
2025-09-23 10:53:17 -04:00
8f162b138d Fix: Client should auto reload after server restarts (#83971)
Port the implementation from pages router to app router.

https://github.com/vercel/next.js/blob/27515900b31bfad83c3ecc65ed2e5d020ec289a6/packages/next/src/client/dev/hot-reloader/pages/websocket.ts

---------

Co-authored-by: devjiwonchoi <[email protected]>
Co-authored-by: JJ Kasper <[email protected]>
2025-09-23 07:45:13 +02:00
Jude GaoandGitHub 7cc0ed1fba Fix: Resolve <Head> PPR resume mismatch by search params (#82587)
The `key` prop on `<Head>` component differs during prerender and a PPR
resume because of search params being part of the key, causing the
resume to treat them as distinct components, hence the error\*. However,
it is necessary semantically to include search params in the key for
`<Head>`, so we will remove the search params from the key during the
resume SSR.

\*Mismatch Error:
```
 ⨯ [Error: Couldn't find all resumable slots by key/index during replaying.
The tree doesn't match so React will fallback to client rendering.]
```
2025-08-12 20:51:34 -04:00
Jude GaoandGitHub cc5e9e6700 Fix: Allow dynamic rendering when root layout is wrapped in Suspense (#82378)
The prelude is empty when the entire app is suspended during prerender.
Typically this indicates a lack of suspense boundary in the app, which
creates no static shell, thus throwing error. However, if the root
layout itself is dynamic but wrapped under a suspense, we need special
logic in this PR to detect that.
2025-08-12 00:18:40 +00:00
Jude GaoandGitHub 4dc34109a4 Fix: Disambiguate Mediapartners-Google user agent (#82536)
`Mediapartners-Google` used to match both `HEADLESS_BROWSER_BOT_UA_RE`
and `HTML_LIMITED_BOT_UA_RE`, causing inconsistent state values for
`getBotType`, `isDomBotUA`, and `isHtmlLimitedBotUA`.
2025-08-11 19:36:18 -04:00
Jude GaoandGitHub 6797a087e5 Fix: Do not force BLOCKING_STATIC_RENDER for DOM bots (#82427)
The issue was that DOM bots with PPR-enabled routes were being forced to
use BLOCKING_STATIC_RENDER mode, which prevented them from using the
fallback cache lookup mechanism. This caused them to generate new
content with isRevalidating: true, which blocks postponed data and
triggers the Math.random() static generation bailout error.

For HTML bots, they keep using BLOCKING_STATIC_RENDER because SSG was
turned off for them and won't see the SSG bailout error. For DOM bots,
they should behave like a normal user.

Fixes NAR-273
2025-08-08 13:03:27 -04:00
Jude GaoandGitHub 9c120306af Fix RSC hash validation for middleware external rewrites (#82176) 2025-07-30 08:55:39 +08:00
Jude GaoandGitHub 5c25087d57 Fix validateRSCRequestHeaders incorrect redirect (#82119)
Found during dogfooding on Vercel that sometimes the RSC validation
fails incorrectly. The root cause was that headers like
`Next-Router-Prefetch` were absent from the header and transferred to
request meta. Eventually we should improve how we retrieve these fields
consistently.
2025-07-28 15:18:20 -04:00
Jude GaoandGitHub d9bcc4a6d3 [Segment Cache] Fix isHeadPartial logic (#81566)
This PR fixed two typos that affected isHeadPartial logic.
2025-07-15 00:34:51 +08:00
Jude GaoandGitHub ed892f70c3 Add regression test for conflicting search and route params (#81249)
Follow-up to https://github.com/vercel/next.js/pull/81209
2025-07-03 21:44:24 -04:00
Jude GaoandGitHub 3bad7cc779 Roll out validateRSCRequestHeaders (#80954) 2025-06-27 02:35:28 +08:00
Jude GaoandGitHub 0e73aeea6a Perf: Use canonicalUrl from prefetch for dynamic RSC requests (#80817)
If a prefetch request hits a 307, the browser follows the redirect, and
you’ll know the final URL after that. Then, during actual navigation,
dynamic data should be fetched from the redirected URL rather than the
original one specified in the link.
2025-06-25 14:27:59 -04:00
Jude GaoandGitHub 6fd6ed1ea2 Check cache busting search params on all RSC requests (#80669)
For all RSC requests, we require the `_rsc` search param to match the
hash of its corresponding RSC headers. In the case where the match
fails, we respond with a redirect to the correct search param. This hash
check only applies to `next start` mode for now.
2025-06-25 12:46:29 -04:00
Jude GaoandGitHub d49c6a4034 overwrite redirect SSG meta.status to 200 for RSC requests (#80391)
For a static route that simply returns a `redirect`:
```
export default function Page() {
  redirect("/about");
}
```
the SSG generates a `.meta` file for the route at build time, that looks
like:
```
{
  "status": 307,
  "headers": {
    "location": "/about"
  }
}
```
On `next start`, if a request matches this route, the status code is
retrieved from the file and returned to the response. This is perfectly
fine for DOC requests. However, if the request is an RSC request, its
RSC payload should have already encoded the redirect instruction:
```
1:"$Sreact.fragment"
2:I[657,[],""]
3:I[8597,[],""]
5:I[5975,[],"OutletBoundary"]
8:I[4429,[],"AsyncMetadataOutlet"]
a:I[5975,[],"ViewportBoundary"]
c:I[5975,[],"MetadataBoundary"]
e:I[1363,[],""]
0:{"P":null,"b":"gelhztYnmFGzccJ4F6F4T","p":"","c":["","rsc-redirect"],"i":false,"f":[[["",{"children":["rsc-redirect",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[null,["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["rsc-redirect",["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":["$L4",null,["$","$L5",null,{"children":["$L6","$L7",["$","$L8",null,{"promise":"$@9"}]]}]]}],{},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","0db7ba866b0656c433aa56ad545d5b104626108ev",{"children":[["$","$La",null,{"children":"$Lb"}],null]}],["$","$Lc",null,{"children":"$Ld"}]]}],false]],"m":"$undefined","G":["$e","$undefined"],"s":false,"S":true}
4:E{"digest":"NEXT_REDIRECT;replace;/about;307;"}
f:"$Sreact.suspense"
10:I[4429,[],"AsyncMetadata"]
d:["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":["$","$L10",null,{"promise":"$@11"}]}]}]
7:null
b:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
6:null
9:{"metadata":[],"error":null,"digest":"$undefined"}
11:{"metadata":"$9:metadata","error":null,"digest":"$undefined"}
```

Specifically,
```
4:E{"digest":"NEXT_REDIRECT;replace;/about;307;"}
```

Hence, it would be fine to simply return 200 status code.

There are two motivations for this change:
1. This new behaviour is consistent with Next.js apps hosted on Vercel.
(I.e., it returns 200 for static RSC even if the `meta.status = 307`)
2. 307 redirect on RSC payload is an obstacle to enabling [RSC
validation](https://github.com/vercel/next.js/pull/80157)
2025-06-19 19:39:00 -04:00
Jude GaoandGitHub 2ffdaafbe9 Revert "(E2E) Log which config file is used for next start" (#80666)
Reverts vercel/next.js#73105
2025-06-18 21:08:49 -04:00
Jude GaoGitHubgraphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
b82ada30b2 guarantee cache busting param correctness (#80381)
[RSC validation](https://github.com/vercel/next.js/pull/80157) requires
`_rsc` search param to match the RSC
[hash](https://github.com/vercel/next.js/blob/06-10-remove_existing_cache_busting_param_and_add_fresh_one/packages/next/src/shared/lib/router/utils/cache-busting-search-param.ts#L3)
of request headers.


To guarantee any request initiated from Next.js meets the criteria, we
are going to remove existing cache busting param and add fresh one
**just in case the pre-existing param does not match the hash**.

Existing E2E tests should cover this change.

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-06-17 18:56:00 -04:00
Jude GaoandGitHub 6492a52b53 re-enable vary header deploy test (#79753)
Since the corresponding change has been released in Vercel CLI, we can
re-enable the test.
2025-05-28 10:40:08 -04:00
Jude GaoandGitHub 5c8f6206b1 Revert "[next-server] skip setting vary header for basic routes" (#79426)
Reverts vercel/next.js#77797
Reinstate the `Vary` header to prevent browsers from incorrectly reusing
RSC responses during bfcache restores.
2025-05-23 16:44:39 -04:00
Jude GaoandGitHub 2b1d7d39cc fix: remove redundant performance.measure usage (#79475)
`performance.measure` here is causing problems but I also do not see the
point of keeping it, so this PR deletes it.

Closes NDX-1050
Fixes https://github.com/vercel/next.js/issues/79188
2025-05-21 17:12:45 -04:00
Jude GaoandGitHub a64130eba1 doc: add build lifecycle hooks documentation (#78842)
Added documentation for the new Build Lifecycle Hooks feature in the
Next.js Compiler, specifically the `runAfterProductionCompile` hook.

https://github.com/vercel/next.js/pull/77345
2025-05-06 14:13:55 +01:00
Jude GaoandGitHub ec6c710845 feat: build lifecycle hooks - afterProductionCompile (#77345)
Add a `runAfterProductionCompile` hook in next.config.js that executes
after production build compilation finishes, but before running
post-compilation tasks like type checking and static page generation.
This hook provides access to project metadata including the project
directory and build output directory, making it useful for third-party
to collect build outputs like sourcemaps.
2025-05-02 08:44:45 -04:00
Jude GaoandGitHub a14d013766 doc: onNavigate follow-up (#77805)
Fix the logic when user explicitly wants to leave the page but
navigation is blocked.
2025-04-04 07:53:45 +08:00
2acdadb418 doc: useLinkStatus doc follow-up (#77790)
`use client` file should not define server components

---------

Co-authored-by: Zack Tanner <[email protected]>
2025-04-04 02:00:13 +08:00
4643bcd4e2 doc: onNavigate (#77647)
<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the
PR.
- Read the Docs Contribution Guide to ensure your contribution follows
the docs guidelines:
https://nextjs.org/docs/community/contribution-guide

### Adding or Updating Examples

- The "examples guidelines" are followed from our contributing doc
https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See
https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->

---------

Co-authored-by: Lee Robinson <[email protected]>
Co-authored-by: Delba de Oliveira <[email protected]>
2025-04-04 01:39:04 +08:00
Jude GaoandGitHub 6fa2d2124b doc: useLinkStatus (#77648) 2025-04-03 20:21:44 +08:00
Jude GaoandGitHub 2737373c3b doc: instrumentation-client (#77649) 2025-04-01 23:14:25 +08:00
Jude GaoandGitHub d851bbc14c Fix: RESTORE_ACTION should not be thenable (#77582)
Respect sync/async actions by reducer. RESTORE_ACTION is sync action so
should not return a `thenable`.
2025-03-28 12:58:39 -04:00
ccd76c961a feat: useLinkStatus (#77300)
# `useLinkStatus` Hook

The `useLinkStatus` hook is primarily useful when:

- Links have `prefetch={false}` set
- Navigation occurs before prefetching has completed
- When React decides to [skip the loading
state](https://react.dev/reference/react/useTransition#preventing-unwanted-loading-indicators)
and https://github.com/vercel/next.js/issues/69625

It provides loading state feedback during these navigation transitions,
preventing pages from appearing "frozen" while new content loads.

## Usage

`useLinkStatus` can be called from any descendant component of `Link`
and it returns `{ pending: true }` before history has updated. After the
URL updates, it returns `{ pending: false }`.

```jsx
// When prefetching is disabled
<Link href="/dashboard/reports" prefetch={false}>
  Reports <LoadingIndicator />
</Link>

function LoadingIndicator() {
  const { pending } = useLinkStatus();
  return pending ? <Spinner /> : null;
}
```

## Notes

- If the link has been prefetched, pending change will be skipped and
remain `{ pending: false }`.
- If `useLinkStatus` is not under any `Link`, it will always return `{
pending: false }`.
- `useLinkStatus` currently does not support Pages Router, so it will
always return `{ pending: false }` in Pages Router.
- When you click multiple links in a short period, only the last link's
pending state is shown

---------

Co-authored-by: Andrew Clark <[email protected]>
2025-03-24 15:50:36 -07:00
Jude GaoandGitHub 31dc9381ad only log when instrumentation client takes too long (#77378)
Only log when the sync code inside instrumentation client takes more
than 16ms, instead of logging every single time.
2025-03-21 17:27:19 -04:00
Jude GaoandGitHub 5b9d66a9b8 clean up useReducer code re dev indicator (#77354)
Follow-up to https://github.com/vercel/next.js/pull/76976

Since we want to make explicit mode check from outside, we can now
remove the implicitly checked one from inside.
2025-03-20 20:24:23 -04:00
Jude GaoandGitHub 608ffdad20 feat: onNavigate for link (#77209) 2025-03-18 14:55:57 -07:00
Jude GaoandGitHub 3c2670df92 log the instrumentation-client execution time (#77121)
Follow up to
https://github.com/vercel/next.js/pull/76916#discussion_r1994126285


![CleanShot 2025-03-14 at
[email protected]](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/rKSEEwxbNzdFs9t0yyxN/13cbdcea-02c2-41b4-9219-103b1dbf545e.png)
2025-03-17 11:12:28 -04:00
Jude GaoandGitHub d41d03547b doc: diff between instrumentation vs instrumentation-client (#77143)
<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the PR.
- Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide

### Adding or Updating Examples

- The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to understand the PR)
- When linking to a Slack thread, you might want to share details of the conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->
2025-03-14 15:17:50 -07:00
Jude GaoandGitHub 4fead14969 Add doc for instrumentation client hook (#77134) 2025-03-14 12:56:53 -07:00
Jude GaoandGitHub 7de4c0728b (feat) support client-side instrumentation (#76916) 2025-03-14 05:18:09 -07:00
Jude GaoandGitHub 8bc2a65fdd track persistent caching usage (#76996) 2025-03-11 15:33:37 -07:00
3fa70738c9 doc: use redirect in client components (#76332)
Co-authored-by: Jimmy Lai <[email protected]>
2025-03-05 10:00:29 +00:00
Jude GaoandGitHub 4bb686dee9 Fix: respond 405 status code on OPTIONS request to SSG page (#76767)
### What?

The behavior of `OPTIONS` requests differs depending on whether the page
is an SSG page or not:

- For **SSG pages**, we return a `405 Method Not Allowed` status code
([#34346](https://github.com/vercel/next.js/pull/34346)).
- Otherwise, when an `OPTIONS` request reaches `doRender`, it returns a
`400 Bad Request`
([#65295](https://github.com/vercel/next.js/pull/65295)).

However, in the first case, handling the error page triggers a
`doRender` call, which inadvertently resets the status code to `400`. We
want to ensure it remains `405`.

To fix this, I propose **skipping the error page rendering for `OPTIONS`
requests on SSG pages** and directly returning `"Method Not Allowed"`.
This also addresses several related issues (see "Why").

### Why?

When an `OPTIONS` request is made to an SSG page:

1. **Rendering an error page is wasteful.** A `405` response doesn’t
need a UI, so skipping the rendering improves efficiency.
2. **The status code is reset incorrectly.** As described in ["What"],
the logic in
[`base-server.ts#L2682`](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/base-server.ts#L2682)
changes the status code to `400` when rendering an error page.
3. **It triggers a fatal error** (`Error: invariant: cache entry
required but not generated`) for projects deployed on Vercel (see:
[NEXT-4000](https://github.com/vercel/next.js/issues/4000)).

### How?

Instead of rendering an error page, we return a **hardcoded HTML
response** with a `"Method Not Allowed"` body.

Closes [NEXT-4000](https://github.com/vercel/next.js/issues/4000).
2025-03-03 17:59:22 -05:00
Jude GaoandGitHub c505a4ca21 exclude AppDevOverlayErrorBoundary from prod build (#76568)
**Test**


Generate a prod build, and search `AppDevOverlayErrorBoundary` in the
build output.

---

Before the change, `main-app` has an occurrence of
`AppDevOverlayErrorBoundary`.


![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/rKSEEwxbNzdFs9t0yyxN/85112448-fd0f-40f1-a948-79e69a97d4ff.png)

After the change, there should be 0 occurrences:


![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/rKSEEwxbNzdFs9t0yyxN/492605a8-3a23-459d-80a6-4f818ac8ef4d.png)
2025-02-26 14:38:28 -05:00
Jude GaoandGitHub 4ceef2ce40 [dev-overlay] adjust Next.js logo stroke color during dev builds (#76351)
This was a style regression: We wanted to use a grey'd out color to
indicate building and the full brightness one for rendering. Original PR
before regression: https://github.com/vercel/next.js/pull/74833
2025-02-21 19:00:08 -05:00
Jude GaoandGitHub cb7bcf3ccc [dev-overlay] expandable error message container (#76297)
When the error message exceeds 200px in height, we want to collapse the
part above 200px, and show a button to expand it.

[CleanShot 2025-02-20 at 16.46.16.mp4 <span
class="graphite__hidden">(uploaded via Graphite)</span> <img
class="graphite__hidden"
src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/rKSEEwxbNzdFs9t0yyxN/ad657511-2c09-4180-85db-be7325f45d2f.mp4"
/>](https://app.graphite.dev/media/video/rKSEEwxbNzdFs9t0yyxN/ad657511-2c09-4180-85db-be7325f45d2f.mp4)

Closes NDX-743
2025-02-20 17:29:20 -05:00
Jude GaoandGitHub 779c0374cf [dev-overlay] use unique font name (#76230)
We [inject a style tag](https://github.com/vercel/next.js/pull/76225)
that downloads Geist fonts from local file system. However, that style
tag is injected to the main DOM because of an
[issue](https://issues.chromium.org/issues/41085401) in Chrome that the
fonts do not work in shadow DOM. We worry that this injected style would
interfere with user's styles, or vice versa. Hence, we are going to name
them with unique prefix to avoid most collision.
2025-02-20 09:19:55 -05:00
Jude GaoandGitHub ef42b84e34 [dev-overlay] use absolute font src url (#76229)
Fix font loading from a non-root URL:

Repro:
```
pnpm next dev test/development/app-dir/owner-stack/
```
and Visit http://localhost:3000/browser/uncaught

Shows
```
GET /browser/__nextjs_font/geist-latin.woff2 404 in 330ms
```
2025-02-19 17:42:57 -05:00
Jude GaoandGitHub 357361bcea Remove hmr socket code from prod build (#76232)
Follow up to https://github.com/vercel/next.js/pull/54078, we wouldn't
want HMR related code in production bundle. Relates to
https://github.com/vercel/next.js/issues/76198 but doesn't solve that
completely.

----
<table>
  <tr>
<td><img
src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/rKSEEwxbNzdFs9t0yyxN/5ed4dfeb-5bc6-4e14-a1e8-efef2d0e0066.png"
width="300"/></td>
<td><img
src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/rKSEEwxbNzdFs9t0yyxN/38e382b2-718d-4a09-b55a-6df8b4865614.png"
width="300"/></td>
  </tr>
  <tr>
<td colspan="2" style="text-align: center;">Size reduced from 122KB to
119KB for a trivial app router application.</td>
  </tr>
</table>
2025-02-19 16:14:18 -05:00
Jude GaoandGitHub bedbbb7395 [dev-overlay] font style backward compat with react 18 (#76225)
Style tag hoisting is not available in React 18 -- see [failed
test](https://github.com/vercel/next.js/actions/runs/13416102637/job/37480399204).
Thus, replace it with a backward-compatible solution.
2025-02-19 13:56:39 -05:00
Jude GaoandGitHub 9966e7e1b3 [dev-overlay] fix Geist fonts (#76166)
### What?

Two issues need to be solved:
1. Font isn't working. Dev overlay uses Geist fonts. Currently does not
work if they are not installed in OS.
2. Even if fonts worked, we would be downloading fonts from Google for
the dev overlay, which is not ideal for slow internet & users with
restricted access to Google.

### Why?

**Reason to (1):** Styles defined inside Shadow DOM cannot contain
`@font-face`. Custom fonts should be defined in the main container and
can be accessed in Shadow DOM. Read this
[post](https://robdodson.me/posts/at-font-face-doesnt-work-in-shadow-dom/).

### How?

To solve (1), we simply lift the font styles outside the Shadow DOM.
To solve (2), we introduce a new dev middleware for the dev-server that
serves the font assets & we modify the taskfile to move the woff2 fonts
to the dist folder.


Closes NDX-834
2025-02-18 23:55:12 -05:00
Jude GaoandGitHub 785e9660d4 Fix: Build error causes infinite loop on new dev overlay in Turbopack (#75984)
### What?

When you enable both Turbopack, and the new dev overlay, you will see
that the dev overlay is frozen and the network tab shows that it is
fetching the stack frames API indefinitely.

### Why?

​During our migration to the new development overlay, we implemented a
refactor to ensure that logic for handling runtime errors is executed
consistently, even in the case of build-time errors. This change
involves invoking the getErrorByType function for build errors. However,
this function attempts to retrieve stack frames for the build-time
error, inadvertently triggering Turbopack to initiate a rebuild.

Once Turbopack completes the rebuild process, it dispatches a Hot Module
Replacement (HMR) event to indicate the presence of a new error. This
event prompts getErrorByType to attempt fetching the stack frames again,
which in turn causes Turbopack to rebuild once more. This creates an
endless loop of rebuilding and error signaling.

You can repro it by running
```
__NEXT_EXPERIMENTAL_NEW_DEV_OVERLAY='true' TURBOPACK=1 pnpm testonly-dev test/development/acceptance-app/editor-links.test.ts
```
with the test file change in this PR. (Important to add that. Otherwise
the test would still complete successfully)

### How?

Do not run the runtime error logic for build errors.


Closes NDX-816
2025-02-13 16:23:06 -05:00
Jude GaoandGitHub 673f0a9647 error code should preserve after stitching (#75929) 2025-02-11 19:28:32 -05:00
Jude GaoandGitHub 2aa2eaadc3 dev error overlay: async boundary for original stack frame call (#75718) 2025-02-10 14:47:45 -05:00
Jude GaoandGitHub 06613427c0 docs: add Chrome debugging port configuration steps (#75845)
This configure step is potentially required for the ports to show up in
the remote targets.
2025-02-10 12:16:27 -06:00