payload-smart-cache
Intelligent, dependency-aware cache invalidation for Next.js + Payload CMS applications.

Overview
payload-smart-cache hooks into Payload's save and publish flow to provide automatic, dependency-aware cache invalidation. It builds a dependency graph from your collection and global relationships and walks it on every change, revalidating all affected Next.js cache tags — including indirectly related collections and globals.
Features
- Dependency graph — automatically discovers relationships between collections, so changing a referenced document revalidates its dependents.
- Tag-based revalidation — precise, granular cache invalidation via Next.js
revalidateTag().
- Versions-aware — for versioned collections, cache invalidation only fires on publish, not on draft saves.
- Request caching utility —
createRequestHandler wraps data-fetching functions with collection/global-level cache tags for automatic revalidation.
Installation
pnpm add payload-smart-cache
Usage
Important: smartCachePlugin scans collection and global fields at config time to auto-discover referenced collections. It must be listed after any plugin that registers collections or injects relationship fields, so those are visible during the scan.
import { buildConfig } from "payload";
import { discussionsPlugin } from "payload-discussions";
import { smartCachePlugin } from "payload-smart-cache";
export default buildConfig({
plugins: [
discussionsPlugin({ collections: ["posts"] }),
smartCachePlugin({
collections: ["pages", "posts"],
globals: ["site-settings"],
}),
],
});
Wrap your data-fetching functions with createRequestHandler so they are cached by collection/global tags and automatically revalidated when those collections or globals change:
import { createRequestHandler } from "payload-smart-cache";
const getPosts = createRequestHandler(
async () => {
const payload = await getPayload({ config });
return payload.find({ collection: "posts" });
},
["posts"],
);
You can pass additional cache options as a third argument:
const getPosts = createRequestHandler(
async () => {
const payload = await getPayload({ config });
return payload.find({ collection: "posts" });
},
["posts"],
{ revalidate: 60 },
);
tags | string[] | [] | Additional cache tags beyond the collection/global slugs. |
revalidate | number | false | false | Time-based revalidation in seconds, or false for tag-based only. |
Options
collections | CollectionSlug[] | [] | Collections to track changes for. Referenced collections are auto-tracked. |
globals | GlobalSlug[] | [] | Globals to track changes for. Referenced collections are auto-tracked. |
disableAutoTracking | boolean | false | Disable automatic tracking of collections referenced via relationship/upload fields. |
onInvalidate | (change) => void | Promise<void> | — | Called when cache invalidation fires for a registered collection ({ type: 'collection', slug, docID }) or global ({ type: 'global', slug }). |
Contributing
This plugin lives in the payload-plugins monorepo.
Development
pnpm install
pnpm --filter payload-smart-cache dev
pnpm --filter sandbox dev
The sandbox/ directory is a Next.js + Payload app that imports plugins via workspace:* — use it to test changes locally.
Code quality
- Formatting & linting — handled by Biome, enforced on commit via husky + lint-staged.
- Commits — must follow Conventional Commits with a valid scope (e.g.
fix(payload-smart-cache): ...).
- Changesets — please include a changeset in your PR by running
pnpm release.
Issues & PRs
Bug reports and feature requests are welcome — open an issue.
License
MIT