---
title: "Permalinks"
description: "Permalink patterns and the permalink engine."
requested_language: ar
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/ar/next/payload/posts/permalinks
version: unreleased (main)
docs_index: https://docs.systhema.app/ar/next/llms.txt
---
> This page isn't translated yet. Showing English.


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

| Token                      | Source                                             |
| -------------------------- | -------------------------------------------------- |
| `{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`.

```ts
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.
