mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #932] [MERGED] fix(cache): serve stale unstable_cache entries in App Router #960
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#960
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/932
Author: @NathanDrake2406
Created: 4/28/2026
Status: ✅ Merged
Merged: 4/28/2026
Merged by: @james-elicx
Base:
main← Head:nathan/unstable-cache-swr📝 Commits (1)
fa2f7d7fix(cache): serve stale unstable_cache entries📊 Changes
5 files changed (+273 additions, -33 deletions)
View changed files
📝
packages/vinext/src/entries/app-rsc-entry.ts(+3 -0)📝
packages/vinext/src/shims/cache.ts(+112 -33)📝
packages/vinext/src/shims/unified-request-context.ts(+1 -0)📝
tests/__snapshots__/entry-templates.test.ts.snap(+18 -0)📝
tests/shims.test.ts(+139 -0)📄 Description
Summary
unstable_cachedistinguish normal App Router requests from cache-regeneration scopes.FETCHentries immediately for normal App Router requests, while scheduling a deduped background refresh throughwaitUntilwhen available.unstable_cacheentries blocking in route/page revalidation scopes so regenerated ISR artifacts are written with fresh data.Why
CacheHandler.get()already preserves time-expiredFETCHentries ascacheState: "stale", butunstable_cachetreated stale entries as a miss and awaited the callback before responding. That put callback latency on every TTL boundary for App Router requests instead of serving stale data while refreshing in the background.This is a meaningful parity/performance fix rather than speculative cleanup: any
unstable_cache(..., { revalidate })entry with a slow callback added foreground latency each time its TTL elapsed.Next.js parity references
unstable_cacheschedulespendingRevalidatesfor stale entries, awaits it only during static generation, and otherwise returns the cached response immediately:github.com/vercel/next.js@ae61573e06/packages/next/src/server/web/spec-extension/unstable-cache.ts (L246-L298)github.com/vercel/next.js@ae61573e06/packages/next/src/server/web/spec-extension/unstable-cache.ts (L330-L387)unstable_cacherevalidation while an ISR page is regenerating:github.com/vercel/next.js@ae61573e06/test/production/app-dir/unstable-cache-foreground-revalidate/unstable-cache-foreground-revalidate.test.ts (L13-L72)FETCHentries stale by age/tags rather than deleting them, which is what makes stale-while-revalidate possible:github.com/vercel/next.js@ae61573e06/packages/next/src/server/lib/incremental-cache/index.ts (L546-L565)Implementation notes
UnifiedRequestContextnow carries anunstableCacheRevalidationmode.background.foreground.foreground, preserving Pages Router and outside-render behavior.Validation
vp test run tests/shims.test.ts -t "unstable_cache serves stale entries"failed before the fix with stale requests blocking on regeneration.vp test run tests/shims.test.ts -t "unstable_cache (serves stale entries|blocks on stale entries|re-fetches when entry is stale)"vp check tests/shims.test.tsvp test run tests/entry-templates.test.tsvp test run tests/unified-request-context.test.tsvp test run tests/shims.test.tsvp test run tests/app-router.test.ts -t "route handler ISR: STALE serves stale data"vp checkvp run vinext#build🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.