payload-revalidate
Edit one document and only the pages that show it go stale — precise Next.js cache revalidation for Payload, no full-cache purges.
@pro-laico/payload-revalidate makes Next.js cache revalidation precise for Payload.
Edit one document and only the pages that show it go stale.
No more purging the whole cache on every content change.
Before: edit an image's alt text, purge the whole cache, every page rebuilds. After: only that image's own cache entry refreshes — everywhere the image appears — while every surrounding page, list, and card entry survives.
pnpm add @pro-laico/payload-revalidateWhat's included
- Surgical invalidation — edit one document and only the entries that render it go stale; every surrounding page, list, and card survives.
- Field-driven busts — each bust is computed from which fields changed, so a title edit refreshes one card, not the whole archive.
- Cache helpers that fetch and tag together — write a getter as
'use cache'plus one finder call; the finder runs the query and tags the entry. - Zero-config sibling defaults — icons, images, mux, fonts, and seed integrate automatically when the plugin is registered last.
- A live dependency map —
/dev/revalidateshows exactly what revalidates when (withpayload-dev-tools).
Requirements
Next.js 16 with Cache Components enabled, on the App Router.
const nextConfig = { cacheComponents: true }This plugin asks you to adopt a getter pattern: each cached read is a 'use cache'
function plus one finder call, and the cache helpers are seeded once with a live Payload
handle. The Quickstart walks the whole path.
Quickstart
Install
pnpm add @pro-laico/payload-revalidateEnable Cache Components
const nextConfig = { cacheComponents: true }Register the plugin last
Add it last in plugins: [], so it can hook collections other plugins contribute.
import { buildConfig } from 'payload'
import { revalidatePlugin } from '@pro-laico/payload-revalidate'
export default buildConfig({
// ...
plugins: [
// ...your other plugins
revalidatePlugin(), // add it LAST
],
})Seed the cache helpers
Seed the helpers once with your app's live Payload session. Export the handle so
getters and manual busters share it. getPayload returns a promise — hand it in as-is;
createCacheHelpers accepts a Payload or Promise<Payload> and awaits it internally, so
there's no top-level await.
import config from '@payload-config'
import { getPayload } from 'payload'
import { createCacheHelpers } from '@pro-laico/payload-revalidate/cache'
export const db = getPayload({ config })
const { findDoc, findDocByID, findIds, findGlobal } = createCacheHelpers(db)Two entry points: the package root exports revalidatePlugin and tagsFor; the /cache
subpath exports createCacheHelpers. The finders and the manual busters come from what
createCacheHelpers(db) returns. See Exports.
Write a getter
Each getter is 'use cache' plus one finder call. The finder runs the query and tags the
entry.
/** THE atomic unit: one doc, one entry, shared by every usage site. */
export async function getPost(id: string | number) {
'use cache'
return findDocByID('posts', id)
}
/** The id-list: membership/order only. Content edits never touch this entry. */
export async function getRecentPostIds(page = 1) {
'use cache'
return (await findIds('posts', { page, limit: 12, sort: '-publishedAt', list: 'recent' })).ids
}Render ids, self-fetch each card
The list renders ids; each card fetches its own doc through the id-keyed getter — one cache entry per card.
async function PostList() {
const ids = await getRecentPostIds()
return ids.map((id) => <PostCard key={id} id={id} />)
}
async function PostCard({ id }: { id: string | number }) {
const post = await getPost(id)
if (!post) return null
return <article>…</article>
}Explore
The atomic model
Why per-doc entries make invalidation surgical, the tag vocabulary, and what busts when.
Writing getters
The finders, their signatures and return shapes, and the low-level primitives.
Examples
Detail pages, lists, globals, drafts, sitemaps, manual rules, and migrating off unstable_cache.
Reference
Plugin options, the full import-path map, and behavior notes.
Troubleshooting
Nothing revalidates, untagged entries, the /dev/revalidate diagnostic map.
Plugin options
Zero-config by default — every option is optional. See Reference for every option, its default, and the full export map.
Troubleshooting
Fix the common video failures fast: stuck-on-preparing uploads, blank admin fields, 403s on signed playback, and skipped seeds.
Atomic model
See exactly what goes stale when you edit a document — the id-keyed entries, the tag names the plugin builds, and a field-by-field map of what each change busts.