Docs
Next

Roles, preview and freshness

Publisher and author roles, live preview and ISR revalidation for posts.

On this page

This page covers who may write and publish posts, how the editor previews them, and how published changes reach every page that shows a post.

Live previewLink to this section

Posts support PayloadCMS Live Preview + the "preview" button, just like Pages — the admin shows the front-end post rendered live as you edit (Posts ships drafts + 800ms autosave, which drive the iframe). Unlike pages (which store a flat fullPath), a post's URL comes from the active permalink pattern, so the preview path is resolved through the permalink engine (buildPostPreviewPath → generatePreviewPath); when the pattern contains {category}, the category slug is looked up from the post's selected category. It's wired on the Posts collection (admin.livePreview.url + admin.preview) — nothing to configure for the default behaviour.

Split admin / front-end domains. When the admin panel lives on a different domain or subdomain than the public site, set customLivePreviewURL so the "preview" button (and the new-tab open) targets the site instead of the admin domain. It's the same option Pages already use:

withSysthema(payloadConfig, {
  posts: true,
  customLivePreviewURL: 'https://www.example.com',
})

Resolution priority inside generatePreviewPath: customLivePreviewURL → NEXT_PUBLIC_SERVER_URL → relative. The live-preview iframe always uses a relative URL (same-origin postMessage); only the new-tab "preview" link uses the base.

Publisher and Author rolesLink to this section

When posts is enabled, two built-in roles register (and surface automatically in the Users role select). They stay hidden when the module is off.

RoleCapabilitiesCannot
publisherposts.*, categories.*, tags.*, posts.publish, global.general-settings.posts.update, uploads.read, uploads.createManage users, pages, or globals
authorposts.create, posts.read, posts.update, posts.seo.update, categories.read, tags.read, uploads.read, uploads.createPublish or delete posts; write taxonomies

The capabilities themselves (posts.*, categories.*, tags.*, posts.seo.update, posts.publish, global.general-settings.posts.update) are registered only when posts is enabled — gated on === true, like emails and cookie consent, so an undefined flag never registers them. admin inherits them via posts.* / categories.* / tags.* / global.*; dev has *.

Posts read access is gated to published content via capabilityOrPublished('posts.read'): an anonymous request to /api/posts (which the archive listing hits client-side) only ever surfaces published posts — even a crafted where[_status][equals]=draft cannot leak drafts. The Categories and Tags taxonomies use publicOrCapability (full public read — they have no draft/published state).

Revalidation (ISR freshness)Link to this section

A post's data is rendered on many surfaces beyond its own page, so the module revalidates all of them on the relevant edits (so an ISR/static site doesn't serve stale listings). Every hook is gated on the module being enabled and on the disableRevalidate context (programmatic seeding via the local API skips it).

Editor actionRevalidates
Publish / unpublish / delete a post, or edit a card-surfaced field (title, excerpt, featuredImage, category, tags, author, postType, publishedAt, slug)the post's own permalink path (+ the old path when it moved) and every listing surface — archive-template Pages, Pages with a posts block, the homepage — and sibling posts whose Related rail shows it (curated relatedPosts or shared category/tags). A body-only edit revalidates just the post's own page (no listing fan-out).
Change the permalink pattern, or toggle show-author / show-date / share (General Settings → Posts)the whole layout (revalidatePath('/', 'layout')) — every post page and every pattern-built link. (New permalink paths are served on-demand; they only become pre-rendered on the next build/full-ISR expiry.)
Rename / re-slug / delete a category or tagthe posts that render it (kicker / chips) + all listings; a category slug change with {category} in the pattern also drops the affected posts' old paths.
Change an author's byline (name / avatar / role), or an upload's file / altthe posts and listing cards that render them.

These run via on-demand revalidatePath (no unstable_cache/tag refactor), centralized in the shared revalidatePostDependents helper. With the Cloudflare integration enabled, each hook also purges the same public URLs from the Cloudflare edge cache, once per save. Note that ISR behavior only manifests in a production build (next build + next start); in dev every route is dynamic.