Cache Lifetimes
Server cache entries share a common model for freshness, tags, invalidation, and storage. These policies are shared by Page Caching, RSC Caching, and Caching in Server Components.
Lifetimes
A server cache entry is fresh until revalidate, stale until expire, and unusable after expire:
| Setting | Behavior |
|---|---|
revalidate | The entry is fresh until this time passes. Afterward, it is stale but can still be served and refreshed. |
expire | The entry is usable until this time passes. Afterward, it must be rendered again. |
Without expire, an entry stays usable for a year, so revalidate alone keeps serving the entry
while it refreshes in the background. Set expire only when a stale entry must stop being served.
When several lifetime settings contribute to one render, the shortest value wins. expire must be
at least as long as revalidate, a shorter value is clamped to revalidate. Lifetimes are capped
at one year.
revalidate=300sexpire=3600sproductsrevalidate=60sexpire=900sproductsinventoryrevalidate=120sexpire=600sinventoryrevalidate=60sexpire=600sproductsinventoryEach cache scope owns its own entry, but settings from a nested scope also contribute to the parent
page and RSC entries. In this example, getProducts and getInventory keep separate entries,
while their shortest revalidate and expire values constrain the parent entries and their tags
are merged into them. Parent settings do not flow down into nested entries.
Tags
A tag is a label shared by entries that should be invalidated together. When a tag is invalidated, every matching entry is treated as expired on its next read and refreshed as needed.
Tags from nested scopes are merged into parent entries, so invalidating a tag of a nested scope will also invalidate the parent scopes.
Server tags belong to server entries, client segment tags are separate and are managed by the client router. See Segment Caching.
cacheLife
Use cacheLife to set the revalidate and optional expire values for the current server cache
scope:
import { cacheLife } from "@rebask/core/cache"
export default async function ProductsPage() {
cacheLife({ revalidate: 300, expire: 3600 })
return <ProductList />
}The scope of a cacheLife call determines which entries receive its settings. In a page or layout,
the settings contribute to the page's HTML and RSC entries. Inside a
"use cache" function, they apply to that function's entry and
flow upward to the containing render's page and RSC entries.
Multiple cacheLife calls are aggregated using the most restrictive lifetime. The smallest
revalidate and expire values are used. expire is kept at least as long as revalidate.
cacheTag
Use cacheTag to associate the current server cache scope with one or more tags:
import { cacheTag } from "@rebask/core/cache"
export async function getProducts() {
cacheTag("products")
return db.products.findAll()
}
export async function getProduct(id: string) {
cacheTag("products", `product:${id}`)
return db.products.find(id)
}Use cacheTag in a page, layout, or any other Server Component to tag the page and RSC entries
produced by that render. It can also be called inside a "use cache" function to tag that
function's entry and contribute the tag to the containing page and RSC entries. Tags are accumulated
on each scope's own entry and also merged into their parent entries.
revalidateTag
Use revalidateTag from server-side code to invalidate every server entry associated with a tag:
"use server"
import { revalidateTag } from "@rebask/core/cache"
export async function updateProducts() {
await db.products.updateAll()
await revalidateTag("products")
}It can be called from Server Functions,
route handlers, and Server Components. The client router's
router.revalidateTag is a separate API
that only revalidates client segments.
When a tag is revalidated, Rebask records the invalidation time. Entries carrying that tag from before the invalidation are treated as expired on their next read and produce a new value.