Decouple route stale time from segment-level data#88834
Merged
acdlite merged 1 commit intovercel:canaryfrom Jan 28, 2026
Merged
Decouple route stale time from segment-level data#88834acdlite merged 1 commit intovercel:canaryfrom
acdlite merged 1 commit intovercel:canaryfrom
Conversation
53a6238 to
cc865ed
Compare
Collaborator
Tests Passed |
cc865ed to
2aa6696
Compare
This was referenced Jan 24, 2026
Refactors segment cache entries to receive their stale time from the server response rather than inheriting from the parent route cache entry. This decouples the lifetime of segment data from the route tree, preparing for future optimizations. When I say "route" here, what I'm referring to is the mapping of URL -> layout/ page hierarchy. Typically this is a predictable mapping based on the App Router's file-based routing conventions; however, it's possible to rewrite the URL to a different internal route path. Conceptually, the cache life of a route corresponds to how often a proxy is expected to dynamically rewrite or redirect a URL. We don't currently expose a way to directly control this, but if we did, you could think of it as being equivalent to adding "use cache" (and cacheLife, cacheTag, etc.) to the `proxy()` function. The point, though, is that the route tree has a different lifetime than data rendered on the page. Route trees change relatively infrequently, like due to a logged in/out state change, or a feature flag change. So we can/should cache them fairly aggressively by default. This is related to an upcoming change where we'll go even further and _predict_ routes we haven't visited yet based on structurally similar routes we've already seen. This PR itself, though, makes no behavioral changes; it just sets up the subsequent steps.
2aa6696 to
bf20c48
Compare
ztanner
approved these changes
Jan 27, 2026
acdlite
added a commit
that referenced
this pull request
Jan 28, 2026
Based on: - #88834 --- Follows from the previous commits that decoupled route stale time from segment data. Now that routes have their own lifecycle, we can simplify the implementation: route stale times are always the static constant, rather than being derived from server-provided values. Route structure is essentially static — it only changes on deploy. The exception is rewrites/redirects in middleware or proxy, which can change routes dynamically based on request state. But we have other strategies for handling those cases (e.g., route interception headers, cache invalidation on auth state changes). This simplification removes the need to thread stale time through various call sites. The `fulfillRouteCacheEntry` function now computes the stale time internally from a `now` timestamp parameter, following the convention used elsewhere in the codebase.
acdlite
added a commit
that referenced
this pull request
Jan 29, 2026
Based on: - #88834 - #88989 --- This implements a partial "vary params" optimization for the segment cache. When a segment doesn't access params on the server, its prefetched data can be reused across different param values. Two cases are handled: 1. Segments without a user-provided layout (only loading.tsx or nothing) 2. Segments with a 'use client' layout The server now includes a varyParams field in segment prefetch responses. When varyParams is an empty Set, the client re-keys the cache entry with Fallback for all param values, making it reusable across different params. This is a stepping stone toward full vary params tracking where Server Components would track which specific params they access during rendering.
acdlite
added a commit
that referenced
this pull request
Jan 29, 2026
Based on: - #88834 - #88989 - #88998 --- Adds optimistic routing, enabling the client to predict route structure for URLs that haven't been prefetched yet. When navigating to a URL like /blog/post-2, if we've previously learned the pattern from /blog/post-1, we can predict the route structure without waiting for a server response. The client learns route patterns from server responses and builds a trie indexed by URL parts. When a cache miss occurs, we check if the URL matches a known pattern. If so, we create a synthetic cache entry from the template, allowing immediate rendering of loading boundaries. Static siblings (like /blog/featured alongside /blog/[slug]) are tracked to avoid incorrect predictions — we only predict dynamic routes when we're confident no static sibling matches.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refactors segment cache entries to receive their stale time from the server response rather than inheriting from the parent route cache entry. This decouples the lifetime of segment data from the route tree, preparing for future optimizations.
When I say "route" here, what I'm referring to is the mapping of URL -> layout/page hierarchy. Typically this is a predictable mapping based on the App Router's file-based routing conventions; however, it's possible to rewrite the URL to a different internal route path.
Conceptually, the cache life of a route corresponds to how often a proxy is expected to dynamically rewrite or redirect a URL. We don't currently expose a way to directly control this, but if we did, you could think of it as being equivalent to adding
use cache(andcacheLife,cacheTag, etc.) to theproxy()function.The point, though, is that the route tree has a different lifetime than data rendered on the page. Route trees change relatively infrequently, like due to a logged in/out state change, or a feature flag change. So we can/should cache them fairly aggressively by default.
This is related to an upcoming change where we'll go even further and predict routes we haven't visited yet based on structurally similar routes we've already seen.
This PR itself, though, makes no behavioral changes; it just sets up the subsequent steps.
Test Plan
No behavioral changes - existing tests should pass.