mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #709] feat(cache): implement Next.js 16 revalidateTag two-phase stale/expired model #788
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#788
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/709
Author: @james-elicx
Created: 3/29/2026
Status: 🔄 Open
Base:
main← Head:opencode/calm-meadow📝 Commits (5)
0c1c468feat(cache): implement Next.js 16 revalidateTag two-phase stale/expired modelf204a9brefactor(cache): address bonk review commentscc43b17fix(cache): match Next.js updateTags branch logic for durations without expire1a32999fix(cache): reuse now variable in MemoryCacheHandler.get for time-based expiry check26f740achore: merge main and fix interface→type lint violations from #716📊 Changes
5 files changed (+629 additions, -69 deletions)
View changed files
📝
packages/vinext/src/cloudflare/kv-cache-handler.ts(+169 -20)📝
packages/vinext/src/shims/cache.ts(+148 -16)📝
packages/vinext/src/shims/next-shims.d.ts(+18 -3)📝
tests/kv-cache-handler.test.ts(+157 -29)📝
tests/shims.test.ts(+137 -1)📄 Description
Summary
Implements full parity with Next.js 16's
revalidateTagAPI, including:TagManifestEntryshape fromnext/src/server/lib/incremental-cache/tags-manifest.external.tsrevalidateTag()is called without a secondprofileargumentexpire > 0is provided: entries are served stale (triggering background regen) until the expire window closes, then become a hard missexpire: 0: nextget()is an immediate cache missKVCacheHandlernow writes{ stale?, expired? }JSON objects instead of plain timestamps; backward-compatible with old plain-timestamp strings viaparseKVTagEntry()Key implementation details
MemoryCacheHandler(packages/vinext/src/shims/cache.ts):tagManifest: Map<string, TagManifestEntry>replacestagRevalidatedAt: Map<string, number>get()checksexpired >= lastModified && expired <= now(hard miss) thenstale >= lastModified(SWR)>=(not>) for both comparisons to handle same-millisecondset()+revalidateTag()callsKVCacheHandler(packages/vinext/src/cloudflare/kv-cache-handler.ts):KVTagEntry/CachedTagEntryinterfacesparseKVTagEntry()helper: parses new JSON format and falls back to legacy plain-timestamp (maps to{ expired: ts })checkTagInvalidation()helper: returns"expired" | "stale" | "fresh"— same>=fix appliedTests added
revalidateTagreturnscacheState: "stale"(SWR, not null)expire: 0causes hard miss{ expired }/{ stale, expired }formatReference
revalidateTagsource:packages/next/src/server/web/spec-extension/revalidate.tsTagManifestEntry+areTagsExpired/areTagsStale:packages/next/src/server/lib/incremental-cache/tags-manifest.external.ts🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.