Caching and revalidation
Every read carries the sync tags it depends on. Use them as cache tags and a publish purges exactly the pages that read the document.
The response envelope carries syncTags: opaque identifiers for the things a result depends on. That is what makes exact invalidation possible instead of a blunt time-based refresh.
const response = await fetch(url, {
next: { revalidate: 60, tags: cacheTags },
})What the tags are
- A dataset-wide tag, always.
- A per-document tag for each document the read addressed by id.
The asymmetry is forced by the cache rather than chosen: a cache entry's tags must be known before the request is made, and a query's result set is not. So a read by id gets a precise tag, and a filtered query gets the dataset tag.
Purging on write
After any committed write, purge the dataset tag and the tags of the documents the write touched:
revalidateTag(datasetTag(projectId, dataset))
for (const id of writtenIds) revalidateTag(documentTag(projectId, dataset, id))Choosing a window
Sixty seconds is the default here, and it is a floor rather than a ceiling: with tag purging in place, the window only matters for changes that happen outside the write path — a database edit by hand, say. Raise it if publishing always goes through the API.
Two habits
- Split reads. A page that reads its own document by id and its listing separately gets one precise tag and one broad one, instead of one broad one.
- Never cache a draft read. Preview must be uncached, or an editor sees the previous minute's work.
