Skip to content

Gate partialFallback behavior behind partialPrefetching flag#96074

Merged
acdlite merged 1 commit into
canaryfrom
acdlite/gate-partial-fallback-on-partial-prefetching
Jul 22, 2026
Merged

Gate partialFallback behavior behind partialPrefetching flag#96074
acdlite merged 1 commit into
canaryfrom
acdlite/gate-partial-fallback-on-partial-prefetching

Conversation

@acdlite

@acdlite acdlite commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

partialFallback is an internal flag in the build output that controls the behavior of ISR. When it's enabled, in a Cache Components app, pages that are not generated at build time are upgraded to a full ISR entry upon the first request.

This is a useful feature but there's a risk it could lead to an explosion in ISR costs, because even a prefetch request is sufficient to trigger an upgrade.

The desired behavior is that we only trigger an upgrade for an actual navigation request, or if a link opts into prefetching with the prefetch prop.

Currently there's no way for ISR to differentiate between a shell prefetch request (no prefetch prop on the link) and an actual prefetch (prefetch={true}). The plan is to introduce additional configuration to the build output that specifies which headers should trigger which operations.

So by default, this PR turns the partialFallback flag back off until the new mechanism is available to us.

However, for apps that opt into Partial Prefetching, we will continue to set partialFallback to true. That's because in a Partial Prefetching app, per-link prefetch requests are always opt-in. So even without additional support at the ISR behavior, we avoid an unexpected surge in ISR costs by not sending the prefetching request in the first place. There will still be a single request per distinct route (not per distinct URL!), which we will optimize later.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Stats from current PR

Warning

No stats were collected for Webpack because its stats job did not complete (it failed, was cancelled, or timed out). The results below only cover the bundlers that finished.

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 813ms 862ms ▁█▂▂▁
Cold (Ready in log) 811ms 825ms ▁█▂▁▁
Cold (First Request) 1.423s 1.413s ▁█▃▁▁
Warm (Listen) 814ms 813ms ▁█▂▁▁
Warm (Ready in log) 807ms 809ms ▁█▂▁▁
Warm (First Request) 1.381s 1.419s ▁█▂▁▁

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 5.622s 5.652s ▁█▄▁▁
Cached Build 5.930s 5.706s ▁█▃▁▁
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
node_modules Size 527 MB 527 MB ▁▁▁██
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
00v6npozcc3c3.js gzip 155 B N/A -
0a-p0meqxynjz.js gzip 10.3 kB N/A -
0avtke4yefj4-.js gzip 13.1 kB N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0nvyq--brb2d1.js gzip 71.1 kB N/A -
0pt5of3ch6d2u.js gzip 13.6 kB N/A -
0xnsdo-6y9r3k.js gzip 5.72 kB N/A -
0yi7is8u4covm.js gzip 8.77 kB N/A -
1aqu9ze6v_-92.js gzip 157 B N/A -
1bhefyyiiy1a1.js gzip 160 B N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1lh1fi2q329kp.js gzip 155 B N/A -
1lsl-hvtjoz38.js gzip 7.4 kB N/A -
1ltc02dslhmu0.js gzip 156 B N/A -
1prv-wg6jgtt2.js gzip 8.77 kB N/A -
1t47vod02e_4a.js gzip 8.75 kB N/A -
1tbq0-klq39t1.js gzip 156 B N/A -
1tf1phijqlx9j.js gzip 220 B 220 B
1tw002sq5bo4l.js gzip 10 kB N/A -
1wlerik1n7zbr.js gzip 8.7 kB N/A -
22vemgj_ppw9g.js gzip 157 B N/A -
28koph4jjzmen.js gzip 45.2 kB N/A -
2lviwqiqxm904.js gzip 3.52 kB N/A -
2pevdqjpbf3xk.js gzip 9.45 kB N/A -
2ppm-9338hg-g.js gzip 155 B N/A -
2qd2anu9eizlz.js gzip 8.75 kB N/A -
2sv39ae5_8vfj.js gzip 8.81 kB N/A -
2utx6n7w65xqa.js gzip 8.7 kB N/A -
2vo_g-1nu597x.js gzip 153 B N/A -
3_gkkw57bfro8.js gzip 168 B N/A -
3-ukivglqkfeq.js gzip 8.78 kB N/A -
325xisqrylugu.js gzip 450 B N/A -
3e9jui3nrs0cq.js gzip 161 B N/A -
3jc9ghvds1spf.js gzip 2.29 kB N/A -
3juwkvkgvywfe.js gzip 10.6 kB N/A -
3kbove7q58uqh.js gzip 13.2 kB N/A -
3qn7vntp30gaj.js gzip 1.47 kB N/A -
3tg5xymt-y3pf.js gzip 157 B N/A -
3y5l7macq6332.js gzip 156 B N/A -
45bnqre7r-j34.js gzip 65.6 kB N/A -
turbopack-0d..qkmb.js gzip 3.81 kB N/A -
turbopack-0m..pdb9.js gzip 3.78 kB N/A -
turbopack-1-..1ho9.js gzip 3.8 kB N/A -
turbopack-1d..316h.js gzip 3.82 kB N/A -
turbopack-1w..lyf1.js gzip 3.81 kB N/A -
turbopack-25..qyhv.js gzip 3.81 kB N/A -
turbopack-2c..lyeg.js gzip 3.81 kB N/A -
turbopack-2h..a-uq.js gzip 3.8 kB N/A -
turbopack-2j..bz11.js gzip 3.81 kB N/A -
turbopack-3-..gj1l.js gzip 3.81 kB N/A -
turbopack-36..evj4.js gzip 3.81 kB N/A -
turbopack-37.._yox.js gzip 3.8 kB N/A -
turbopack-3p..5n5c.js gzip 3.81 kB N/A -
turbopack-41..w-sa.js gzip 3.81 kB N/A -
030a1njeh5b77.js gzip N/A 10 kB -
0g4_k2uc6wv4q.js gzip N/A 157 B -
0gks75us8x8np.js gzip N/A 156 B -
0ot0qt5np20h7.js gzip N/A 8.78 kB -
1_0n9btq9p4ce.js gzip N/A 156 B -
1-qxxhh8-axib.js gzip N/A 45.2 kB -
12km8nr29deej.js gzip N/A 152 B -
12m9rr7_7cexd.js gzip N/A 8.7 kB -
186r3y_rfvr0b.js gzip N/A 8.78 kB -
19v97848yrjp7.js gzip N/A 8.81 kB -
1em_c2iwtphkh.js gzip N/A 155 B -
1j9dy_1o47w3f.js gzip N/A 157 B -
1k4eu86-nhh6g.js gzip N/A 156 B -
1nd_0rwgz2ozk.js gzip N/A 9.45 kB -
1oi9pltr_e10m.js gzip N/A 10.6 kB -
1rd9tzqgzsz2w.js gzip N/A 8.77 kB -
1rq1g_cwv642d.js gzip N/A 10.3 kB -
1sek4rdapnadp.js gzip N/A 157 B -
1uojw_uabeg93.js gzip N/A 450 B -
1w-7lusgyl81y.js gzip N/A 8.7 kB -
2-kdoq-jy_crq.js gzip N/A 7.41 kB -
21h56wdn9zddo.js gzip N/A 8.75 kB -
23m4n1cp16_my.js gzip N/A 158 B -
26urb3nj-ua41.js gzip N/A 71.1 kB -
2caur9q46_a46.js gzip N/A 160 B -
2d_gfdd2kvo3j.js gzip N/A 155 B -
2lg10omv7xu14.js gzip N/A 3.52 kB -
2ovff1533zvno.js gzip N/A 13.2 kB -
2s4z8jy0z7v93.js gzip N/A 1.46 kB -
2y6gb5bs4mnam.js gzip N/A 8.75 kB -
341h71ln1jpl3.js gzip N/A 2.29 kB -
34ttpt_n7605h.js gzip N/A 5.72 kB -
36ckfq9o-ys-a.js gzip N/A 13.1 kB -
3djafohg3a3jg.js gzip N/A 161 B -
3vdh6_u50pu5t.js gzip N/A 13.6 kB -
3vughx3b6vlec.js gzip N/A 65.6 kB -
3yr5uv4qtknye.js gzip N/A 169 B -
turbopack-04..uq8-.js gzip N/A 3.78 kB -
turbopack-0q..2a0a.js gzip N/A 3.81 kB -
turbopack-0w..pdzm.js gzip N/A 3.81 kB -
turbopack-1_..muub.js gzip N/A 3.8 kB -
turbopack-1d..c7mz.js gzip N/A 3.8 kB -
turbopack-1j..b3jd.js gzip N/A 3.81 kB -
turbopack-1s..sjan.js gzip N/A 3.81 kB -
turbopack-2b..8l3_.js gzip N/A 3.8 kB -
turbopack-2q..n442.js gzip N/A 3.81 kB -
turbopack-2t..t3xp.js gzip N/A 3.82 kB -
turbopack-2z..c636.js gzip N/A 3.8 kB -
turbopack-3_..zctb.js gzip N/A 3.8 kB -
turbopack-39.._x1-.js gzip N/A 3.81 kB -
turbopack-3e..733c.js gzip N/A 3.81 kB -
Total 448 kB 448 kB ⚠️ +37 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 780 B 778 B
Total 780 B 778 B ✅ -2 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 433 B 431 B
Total 433 B 431 B ✅ -2 B

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 366 kB 366 kB
app-page-exp..prod.js gzip 202 kB 202 kB
app-page-tur...dev.js gzip 365 kB 365 kB
app-page-tur..prod.js gzip 202 kB 202 kB
app-page-tur...dev.js gzip 362 kB 362 kB
app-page-tur..prod.js gzip 200 kB 200 kB
app-page.run...dev.js gzip 362 kB 362 kB
app-page.run..prod.js gzip 200 kB 200 kB
app-route-ex...dev.js gzip 81.8 kB 81.8 kB
app-route-ex..prod.js gzip 55.6 kB 55.6 kB
app-route-tu...dev.js gzip 81.8 kB 81.8 kB
app-route-tu..prod.js gzip 55.6 kB 55.6 kB
app-route-tu...dev.js gzip 81.4 kB 81.4 kB
app-route-tu..prod.js gzip 55.4 kB 55.4 kB
app-route.ru...dev.js gzip 81.4 kB 81.4 kB
app-route.ru..prod.js gzip 55.4 kB 55.4 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 45.4 kB 45.4 kB
pages-api-tu..prod.js gzip 34.1 kB 34.1 kB
pages-api.ru...dev.js gzip 45.4 kB 45.4 kB
pages-api.ru..prod.js gzip 34.1 kB 34.1 kB
pages-turbo....dev.js gzip 54.9 kB 54.9 kB
pages-turbo...prod.js gzip 39.7 kB 39.7 kB
pages.runtim...dev.js gzip 54.8 kB 54.8 kB
pages.runtim..prod.js gzip 39.7 kB 39.7 kB
server.runti..prod.js gzip 67.8 kB 67.8 kB
use-cache-pr...dev.js gzip 71.6 kB 71.6 kB
use-cache-pr...dev.js gzip 71.6 kB 71.6 kB
use-cache-pr...dev.js gzip 69.9 kB 69.9 kB
use-cache-pr...dev.js gzip 69.9 kB 69.9 kB
Total 3.51 MB 3.51 MB ✅ -2 B
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/0246bdca2e14558b4602861dafb2eabd058c10ff/next

Commit: 0246bdc

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Tests Passed

Commit: 0246bdc

`partialFallback` is an internal flag in the build output that controls
the behavior of ISR. When it's enabled, in a Cache Components app, pages
that are not generated at build time are upgraded to a full ISR entry
upon the first request.

This is a useful feature but there's a risk it could lead to an
explosion in ISR costs, because even a prefetch request is sufficient to
trigger an upgrade.

The desired behavior is that we only trigger an upgrade for an actual
navigation request, or if a link opts into prefetching with the
`prefetch` prop.

Currently there's no way for ISR to differentiate between a shell
prefetch request (no prefetch prop on the link) and an actual prefetch
(`prefetch={true}`). The plan is to introduce additional configuration
to the build output that specifies which headers should trigger which
operations.

So by default, this PR turns the `partialFallback` flag back off until
the new mechanism is available to us.

However, for apps that opt into Partial Prefetching, we will continue to
set `partialFallback` to true. That's because in a Partial Prefetching
app, per-link prefetch requests are always opt-in. So even without
additional support at the ISR behavior, we avoid an unexpected surge in
ISR costs by not sending the prefetching request in the first place.
There will still be a single request per distinct route (not per
distinct URL!), which we will optimize later.
@acdlite
acdlite force-pushed the acdlite/gate-partial-fallback-on-partial-prefetching branch from 39ee69b to 0246bdc Compare July 22, 2026 18:44
@acdlite acdlite changed the title Only emit partialFallback in build output when partialPrefetching is enabled Gate partialFallback behavior behind partialPrefetching flag Jul 22, 2026
@acdlite
acdlite requested review from gnoff and unstubbable July 22, 2026 19:22
@acdlite
acdlite marked this pull request as ready for review July 22, 2026 20:48
@acdlite
acdlite merged commit 203177b into canary Jul 22, 2026
128 of 129 checks passed
@acdlite
acdlite deleted the acdlite/gate-partial-fallback-on-partial-prefetching branch July 22, 2026 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants