Revalidation
What each save revalidates, skipping it in scripts, and manual revalidation.
On this page
Systhema wires Next.js cache revalidation hooks so editor changes appear without a manual rebuild. The triggers:
- Header or Footer global saved (published) → flushes the
/layout cache, so every page revalidates on next request. - General Settings global saved → tab-aware:
- Pages, SEO, or Cookie Consent tab → flush the
/layout cache (every page revalidates — SEO defaults affect every page's metadata). - Emails tab → no revalidation (email settings don't affect page renders).
- Pages, SEO, or Cookie Consent tab → flush the
- Page saved or deleted → revalidates that page's own path; if it is the currently configured homepage,
/is revalidated too. - Form saved or deleted (from
@payloadcms/plugin-form-builder) → revalidates only the published Pages that embed that form via a form block — not the whole site. Draft-only saves are skipped. - Upload's alt text changed → flushes the
/layout cache. An image can appear anywhere (hero backgrounds, blocks, inline lexical nodes), so which pages embed it isn't reliably queryable — a site-wide flush guarantees every page showing the image picks up the new alt.
This is a behaviour change from versions that flushed on every general-settings save. If you have custom afterChange hooks on a global, check whether they should be restricted to specific tabs.
Posts, categories, tags and authors have their own fan-out; see Revalidation (ISR freshness). With the Cloudflare integration on, every revalidation also purges the edge cache; see Auto-purge.
Localized sitesLink to this section
Localized hooks invalidate the internal catch-all route, not the displayed public pathname. contentLocaleInternalPath() produces /<locale><pathname> for exact-one-locale, as-needed, always, and domain routing, while locale-off keeps the original pathname. Keep contentLocalePath() and absolute public-href helpers for rendered links, canonical metadata, and sitemaps; an unprefixed public path is not a safe locale-specific revalidation key. (contentLocalePath / contentLocaleInternalPath are @systhemaui/payload/next's content-locale-scoped wrappers around @systhemaui/core's getSysthemaLocalizedPathname / getSysthemaInternalLocalePathname — see Frontend locales.)
Skipping revalidation in scripts (context.disableRevalidate)Link to this section
revalidatePath() only works inside a Next.js request — called from a seed script, a migration, or any other Local API program it throws Invariant: static generation store missing. Because afterChange runs inside Payload's transaction, that throw rolls the write back: the script reports success and the database is unchanged.
So every write from a script should carry the opt-out:
await payload.update({
collection: 'forms',
id,
data,
overrideAccess: true,
context: { disableRevalidate: true },
})Every Systhema revalidation hook honours it — pages, posts, categories, tags, components, forms, redirects, users, uploads, and the globals. (Before 1.7, the forms, redirects, components and upload hooks did not, so seeding those collections needed an error-swallowing wrapper. Drop the wrapper and pass the context instead.) Since a script's writes never revalidate, finish by calling POST /sys/revalidate with { "paths": "*" }.
Manual revalidationLink to this section
For the "something looks stale, refresh it now" case there are two on-demand entry points, both backed by the same internal revalidateAllPublishedPages helper (enumerate published Pages → revalidate each path, plus / when a homepage is configured):
POST /sys/revalidate— machine-facing, authenticated with theSYSTHEMA_API_SECRETbearer token (for scripts and cron). Body{ "paths": "*" }revalidates every published page;{ "paths": ["/a", "/b"] }targets specific paths. Returns{ revalidated, count }.- General Settings → Troubleshoot → "Revalidate all pages" — the same
paths: "*"behaviour, gated on a logged-in admin session instead of the API secret. See Troubleshoot tab.