Docs

This page isn't translated yet

Permalinks

Permalink patterns and the permalink engine.

Single posts resolve through a WordPress-style permalink pattern. Supported tokens:

TokenSource
{slug}the post slug (always present)
{category}the post's (single) category slug
{type}the postType value
{year} {month} {day}derived from publishedAt (month/day zero-padded)
{id}the post id

The default is /posts/{slug}. Set a code-level default via posts.permalink; editors can override it at runtime in General Settings → Posts → Permalink pattern.

The engine (buildPermalink / matchPermalink, exported from @systhemaui/payload) is pure and dependency-free. Two important behaviours:

  • Build/match symmetry. When any token a pattern references resolves to empty for a post (e.g. a category-less post under /{category}/{slug}), buildPermalink falls back to the default /posts/{slug} rather than dropping the segment — a dropped segment would yield a URL matchPermalink (exact segment count) couldn't round-trip, so the post would 404 at its own URL. {slug} always resolves, so the default is always buildable.
  • Pages win. Posts are matched after the exact-path Pages query. A Page at /blog always wins over a post whose permalink would also produce /blog.
import { buildPermalink, matchPermalink } from '@systhemaui/payload'

buildPermalink('/{category}/{slug}', { slug: 'golf-r-2025', category: { slug: 'reviews' } })
// → '/reviews/golf-r-2025'

matchPermalink('/{category}/{slug}', '/reviews/golf-r-2025')
// → { tokens: { category: 'reviews', slug: 'golf-r-2025' } }

matchPermalink is purely structural — it does not verify the captured values correspond to a real post. The router queries by {slug} (or {id}) then verifies any captured {category}/{type}/date tokens against the result, so a wrong-token URL 404s.