Blog, docs and changelog

The blog, these docs and the changelog are Markdoc files in apps/web/content. How they are organised, their fields, and the showcase list.

Last updated

/blog, /docs and /changelog render content through a CMS client chosen by CMS_CLIENT:

  • keystatic (the value in apps/web/.env): Markdoc files in the repository.
  • wordpress: posts from a WordPress site at WORDPRESS_API_URL.

The content folder

With Keystatic, content lives in apps/web/content/ (set by NEXT_PUBLIC_KEYSTATIC_CONTENT_PATH=./content):

FolderPage
posts//blog/<file name>
documentation//docs/<folder>/<file name>
changelog//changelog/<file name>
showcase/products.json/showcase (read directly, not through the CMS)

Every published post, doc page and changelog entry is added to the sitemap, with publishedAt as its last-modified date.

Fields

Each .mdoc file starts with front matter. The schema is in packages/cms/keystatic/src/keystatic.config.ts:

FieldUsed for
titlePage title
descriptionSubtitle, card text and meta description
publishedAtDate (YYYY-MM-DD). Blog and changelog are sorted by it, newest first
statusOnly published entries are shown. Also draft, review, pending
orderPosition in the docs sidebar
labelShorter name for the docs sidebar
imageCover image for posts, from public/site/images
categories, tagsLists of strings
collapsible, collapsedDocs only: make a sidebar section fold

How the docs sidebar is built

A folder with a file of the same name is a section: documentation/billing/billing.mdoc is the Billing page, and the other files in documentation/billing/ appear under it. Sections and pages are sorted by order. The /docs landing page shows one card per section.

Writing

The body is Markdoc, which reads like Markdown: headings, lists, links, code blocks, tables and images work. No custom Markdoc tags are registered; add your own in packages/cms/keystatic/src/custom-components.tsx.

The Keystatic editing UI is not mounted, so you edit the files directly (or let your agent do it). pnpm turbo gen keystatic adds the admin routes and the @keystatic/next dependency if you want an editor. Storage defaults to local files; NEXT_PUBLIC_KEYSTATIC_STORAGE_KIND can be github or cloud with the related KEYSTATIC_* variables.

The showcase list

content/showcase/products.json is an array of products checked against apps/web/app/[locale]/(marketing)/showcase/_lib/showcase.schema.ts: slug, name, tagline, url, makerName, optional makerUrl, category, platforms, launchedAt, featured and an optional logo. The form on /showcase emails submissions to CONTACT_EMAIL. You review them and add the ones you accept to the file. An empty array shows a "no products yet" message.

Live demo

Resets hourly

Get the kit