Skip to content

fix(middleware): upgrade Next.js 15.5 and fix middleware discovery#16687

Merged
sergical merged 16 commits into
masterfrom
fix/middleware-env-var-fallback
Mar 5, 2026
Merged

fix(middleware): upgrade Next.js 15.5 and fix middleware discovery#16687
sergical merged 16 commits into
masterfrom
fix/middleware-env-var-fallback

Conversation

@sergical

@sergical sergical commented Mar 4, 2026

Copy link
Copy Markdown
Member

DESCRIBE YOUR PR

Upgrades Next.js 15.1 → 15.5.12 and fixes middleware + 404 page issues.

Middleware moved to project root: Next.js discovers middleware by computing rootDir from the location of pages/ and app/ directories, then scanning that root for middleware.ts. With both pages/ and app/ at the project root, rootDir = project root, so src/middleware.ts was never found — resulting in an empty middleware manifest and no redirects. Moving middleware.ts to the project root fixes discovery.

Changes

  • Upgrade Next.js 15.1 → 15.5.12
  • Move src/middleware.tsmiddleware.ts (project root) for correct discovery
  • Fix 404 page to show DevelopDocsHeader on develop docs
  • Filter falsy children in CodeTabs (Next.js 15.5 compat)
  • Add middleware redirect unit tests
  • Update all references to new middleware location (scripts, CI, docs)

IS YOUR CHANGE URGENT?

Help us prioritize incoming PRs by letting us know when the change needs to go live.

  • Urgent deadline (GA date, etc.):
  • Other deadline:
  • None: Not urgent, can wait up to 1 week+

SLA

  • Teamwork makes the dream work, so please add a reviewer to your PRs.
  • Please give the docs team up to 1 week to review your PR unless you've added an urgent due date to it.
    Thanks in advance for your help!

PRE-MERGE CHECKLIST

Make sure you've checked the following before merging your changes:

  • Checked Vercel preview for correctness, including links
  • PR was reviewed and approved by any necessary SMEs (subject matter experts)
  • PR was reviewed and approved by a member of the Sentry docs team

Co-Authored-By: Claude noreply@anthropic.com

@vercel

vercel Bot commented Mar 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
develop-docs Ready Ready Preview, Comment Mar 5, 2026 3:47pm
sentry-docs Ready Ready Preview, Comment Mar 5, 2026 3:47pm

Request Review

@sergical sergical changed the title fix(middleware): add env var fallback for Node.js runtime feat(middleware): re-land Node.js runtime with env var fix Mar 4, 2026
Comment thread src/middleware.test.ts Outdated
@sergical

sergical commented Mar 4, 2026

Copy link
Copy Markdown
Member Author

Fixed in e905e35 — now using vi.stubEnv/vi.unstubAllEnvs consistently instead of replacing process.env with a plain object. Good catch.

Comment thread src/middleware.test.ts Outdated
Comment thread src/middleware.test.ts Outdated
sergical and others added 10 commits March 4, 2026 18:08
DEVELOPER_DOCS_ is inlined at build time for edge middleware but not
available at runtime in Node.js middleware. Fall back to reading
NEXT_PUBLIC_DEVELOPER_DOCS directly so redirects work in both runtimes.

Also adds middleware redirect tests covering both env var paths and
pass-through behavior.

Co-Authored-By: Claude <noreply@anthropic.com>
Re-applies the changes from #16642 (reverted in #16685) with the env var
fix in place: middleware now falls back to NEXT_PUBLIC_DEVELOPER_DOCS
when DEVELOPER_DOCS_ isn't available at runtime.

Changes:
- Upgrade Next.js 15.1 → 15.5.12
- Enable experimental.nodeMiddleware in next.config.ts
- Set runtime: 'nodejs' in middleware config
- Move pages/ to root (required by Next.js 15.5 node middleware)
- Filter falsy children in CodeTabs (Next.js 15.5 compat)

Co-Authored-By: Claude <noreply@anthropic.com>
Don't assert specific redirect destinations — just verify the correct
redirect set is active based on env vars. Uses localhost as base URL
since no server is involved (pure unit test of the middleware function).

Co-Authored-By: Claude <noreply@anthropic.com>
Node.js middleware can read process.env at runtime, so the
DEVELOPER_DOCS_ indirection via next.config.ts env field is no longer
needed. Read NEXT_PUBLIC_DEVELOPER_DOCS directly and remove the
now-unused env config.

Co-Authored-By: Claude <noreply@anthropic.com>
Addresses review feedback — replacing process.env with a plain object
breaks Node.js's special proxy behavior. Use vi.stubEnv/unstubAllEnvs
consistently to manipulate env vars in tests.

Co-Authored-By: Claude <noreply@anthropic.com>
NEXT_PUBLIC_ vars aren't automatically available in Node.js middleware
at runtime. Re-add the next.config.ts env field (renamed DEVELOPER_DOCS_
to DEVELOPER_DOCS) to inline the value at build time, with
NEXT_PUBLIC_DEVELOPER_DOCS as a runtime fallback.

Co-Authored-By: Claude <noreply@anthropic.com>
importMiddleware calls vi.unstubAllEnvs() before loading the module,
which undoes the beforeEach stub. Remove the dead code.

Co-Authored-By: Claude <noreply@anthropic.com>
Next.js 15.5 stabilized Node.js middleware — only `runtime: 'nodejs'`
in the middleware config export is needed. The experimental flag was
for pre-15.5 canary and was being rejected with "Unrecognized key".

Co-Authored-By: Claude <noreply@anthropic.com>
The delete calls bypass Vitest's stub tracking. Save original values
before deleting and restore them after import so subsequent tests
aren't affected.

Co-Authored-By: Claude <noreply@anthropic.com>
Node.js middleware runs at the origin, so Vercel's CDN serves prerendered
pages without invoking it — breaking develop-docs redirects. Edge middleware
runs before cache at the CDN edge, ensuring redirects always fire.

Co-Authored-By: Claude <noreply@anthropic.com>
…covery

Next.js 15.5 computes rootDir from pagesDir/appDir and expects middleware
at that root. With pages/ and app/ at project root, middleware must also be
at root (not src/) for the middleware manifest to be populated.

Also adds conditional DevelopDocsHeader to 404 page and updates all
references to the new middleware.ts location.

Co-Authored-By: Claude <noreply@anthropic.com>
@sergical
sergical force-pushed the fix/middleware-env-var-fallback branch from 2ce71de to 4d61d76 Compare March 4, 2026 23:15
@sergical

sergical commented Mar 4, 2026

Copy link
Copy Markdown
Member Author

External links is expected to fail since the middleware file hasn't moved yet.
Spotchecked redirects and it seems to be worked as expected

@chargome chargome left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for the follow-up 🥇

Comment thread package.json Outdated
Co-authored-by: Charly Gomez <charly.gomez@sentry.io>
const codeBlocks = Array.isArray(children) ? [...children] : [children];
const codeBlocks = (Array.isArray(children) ? [...children] : [children]).filter(
child => child?.props
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty codeBlocks after filtering causes runtime crash

Medium Severity

The new .filter(child => child?.props) on codeBlocks can produce an empty array, but no guard exists before accessing codeBlocks[selectedTabIndex] later in the component. If all children are falsy (which is why the filter was added — Next.js 15.5 compat), possibleChoices will be empty, and the destructuring ({props: {title, language}}) in .map() won't error on an empty array, but codeBlocks[selectedTabIndex] will be undefined, causing showSigninNote(undefined) and rendering undefined in the JSX. More critically, if only some children are filtered out, possibleChoices and codeBlocks arrays stay in sync, but the selectedTabIndex from global context could now be out of bounds for the shorter array.

Fix in Cursor Fix in Web

sergical and others added 2 commits March 5, 2026 10:34
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment thread app/not-found.tsx
<div className="tw-app">
<Header pathname="/" searchPlatforms={[]} noSearch platforms={[]} />
{isDeveloperDocs ? (
<DevelopDocsHeader pathname="/" searchPlatforms={[]} />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate search boxes on developer docs 404 page

Medium Severity

The DevelopDocsHeader is rendered without the noSearch prop, so it will display its own search bar in the header. The page also renders a separate Search component with autoFocus in the main content area below. The Header for user docs explicitly passes noSearch to avoid this duplication, but the DevelopDocsHeader call omits it, resulting in two search boxes visible simultaneously on medium+ screens for developer docs 404 pages.

Additional Locations (1)

Fix in Cursor Fix in Web

@sergical
sergical merged commit da6c9f8 into master Mar 5, 2026
18 of 19 checks passed
@sergical
sergical deleted the fix/middleware-env-var-fallback branch March 5, 2026 16:41
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants