nextjs - ✅(Solved) Fix Prefetched SSG/ISR routes always return 200 instead of 304 since v15.4.1 [2 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#85121Fetched 2026-04-08 02:17:20
View on GitHub
Comments
2
Participants
2
Timeline
12
Reactions
1
Author
Timeline (top)
labeled ×3commented ×2cross-referenced ×2subscribed ×2

Fix Action

Fixed

PR fix notes

PR #85643: Fix/prefetch always 200

Description (problem / solution / changelog)

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

Starting from Next.js v15.4.1 (commit 256cd5b571), prefetch requests for SSG/ISR pages always returned 200 OK status codes instead of 304 Not Modified, even when the content hadn't changed. This forced full payload downloads on every prefetch (e.g., on hover or in-viewport), unnecessarily increasing CDN traffic and bandwidth costs.

Root Cause: In commit 256cd5b571 ("Add response handling inside handlers"), the Pages Router handler was modified to create RenderResult instances with Buffer.from() for cached content:

The problem: RenderResult.isDynamic returns true when the response is a Buffer (not a string):

public get isDynamic(): boolean {
  return typeof this.response !== 'string'  // Buffer !== 'string' → true
}

Test repository for testing changes (to prevent version conflicts): https://github.com/denesbeck/next-test-304 Simply package the Next.js version from this branch into the repository. Then, run npm run build and npm run start.

Note: Firefox may show different behavior as it handles prefetch caching with different strategies that don't always use the same HTTP cache validation mechanisms as Chrome. However, the server-side fix is correct and working as expected - the server properly generates ETags and returns 304 responses when appropriate. The difference is in how browsers choose to send (or not send) the If-None-Match header for prefetch requests.

Changed files

  • packages/next/src/server/route-modules/pages/pages-handler.ts (modified, +11/-17)
  • test/production/prefetch-304-response/app/pages/index.js (added, +12/-0)
  • test/production/prefetch-304-response/app/pages/ssg.js (added, +16/-0)
  • test/production/prefetch-304-response/index.test.ts (added, +73/-0)

PR #90304: Fix(pages-router): restore Content-Length and ETag for /_next/data/ JSON responses

Description (problem / solution / changelog)

What

Removes the Buffer.from() wrapper when constructing RenderResult for /_next/data/ JSON responses in the Pages Router handler.

Why

PR #80189 introduced Buffer.from(JSON.stringify(result.value.pageData)) when building the data response. Since RenderResult.isDynamic checks typeof this.response !== 'string', passing a Buffer (not a string) caused it to return true, making sendRenderResult treat the response as a dynamic stream — skipping Content-Length and ETag generation and falling back to Transfer-Encoding: chunked.

This is a regression from v15.4.0 and breaks CDN-side compression for self-hosted deployments (e.g. CloudFront requires Content-Length to compress origin responses on-the-fly).

Fix

- Buffer.from(JSON.stringify(result.value.pageData)),
+ JSON.stringify(result.value.pageData),

Testing

Affected Area

  • Pages Router — /_next/data/ responses only
  • No impact on App Router
  • Single-line change, minimal blast radius

Fixes #90281

Changed files

  • AGENTS.md (modified, +4/-4)
  • packages/next/src/server/route-modules/pages/pages-handler.ts (modified, +11/-17)
  • test/e2e/prerender.test.ts (modified, +16/-4)

Code Example

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Pro
  Available memory (MB): 32478
  Available CPU cores: 32
Binaries:
  Node: 22.18.0
  npm: 10.9.3
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 15.4.1 // There is a newer version (15.5.6) available, upgrade recommended!
  eslint-config-next: N/A
  react: 19.1.0
  react-dom: 19.1.0
  typescript: N/A
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/iiegor/next-prefetch-http-status-repro

To Reproduce

  1. Clone the reproduction repo:
    https://github.com/iiegor/next-prefetch-http-status-repro

  2. Install dependencies:
    npm install

  3. Build the app:
    npm run build

  4. Start the app:
    npm run start

  5. Open the app in your browser and inspect the network panel.

  6. Hover over a <Link> that points to an SSG or ISR page.

  7. Observe:

    • On Next.js ≤ v15.4.0: first prefetch returns 200, subsequent prefetches return 304.
    • On Next.js ≥ v15.4.1: all prefetches return 200.

Current vs. Expected behavior

Current behavior Starting from v15.4.1, every prefetched SSG/ISR route request returns a 200 response, even when the page hasn’t changed. This forces full payload downloads on every prefetch (e.g., on hover or in-viewport prefetch), increasing CDN traffic and costs.

Expected behavior Prefetched SSG routes with a valid cached version should return a 304 Not Modified response, as they did in previous releases (≤ v15.4.0), allowing browsers and CDNs to serve cached content efficiently.

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Pro
  Available memory (MB): 32478
  Available CPU cores: 32
Binaries:
  Node: 22.18.0
  npm: 10.9.3
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 15.4.1 // There is a newer version (15.5.6) available, upgrade recommended!
  eslint-config-next: N/A
  react: 19.1.0
  react-dom: 19.1.0
  typescript: N/A
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Pages Router, Linking and Navigating

Which stage(s) are affected? (Select all that apply)

next start (local), Other (Deployed), Vercel (Deployed)

Additional context

The issue is reproducible both locally (during development and production builds) and in self-hosted deployments running under Docker.

extent analysis

TL;DR

Upgrading to a newer version of Next.js may resolve the issue of prefetched SSG routes returning a 200 response instead of a 304 Not Modified response.

Guidance

  • Verify that the issue persists after upgrading to the latest version of Next.js (currently 15.5.6) to ensure it's not a resolved bug.
  • Check the next.config.js file for any custom configurations that might be interfering with the prefetch behavior.
  • Test the application with different caching strategies to see if the issue is related to a specific caching setup.
  • Consider opening an issue on the Next.js GitHub repository if the problem persists after upgrading, as it may be a regression introduced in version 15.4.1.

Example

No code snippet is provided as the issue seems to be related to a version-specific bug rather than a code error.

Notes

The issue seems to be specific to Next.js version 15.4.1 and later, and upgrading to a newer version may resolve the issue. However, without further investigation, it's unclear if this is a bug or an intended change in behavior.

Recommendation

Apply workaround: Upgrade to the latest version of Next.js (15.5.6) to potentially resolve the issue, as the current version (15.4.1) may contain a bug that's causing the unexpected behavior.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix Prefetched SSG/ISR routes always return 200 instead of 304 since v15.4.1 [2 pull requests, 2 comments, 2 participants]