Configuration
Reference for astro.config.ts, publier.config.yaml, theme.yaml, and meta.yaml.
Publier uses the following configuration files. The scaffolder creates the project-level files for you.
| File | What it controls | Required |
|---|---|---|
astro.config.ts | Astro integrations and Vite plugins | ✓ |
publier.config.yaml | Site name, nav, search trigger, analytics, fonts, snippets | ✓ — at least site.name |
theme.yaml | Color preset + brand overrides | — |
meta.yaml (per folder) | Optional metadata input for a custom route using readMetaYaml() | — |
astro.config.ts
docsShell() wires the Publier pipeline — theme tokens, callouts, remark/rehype plugins, default routes, and Mermaid auto-detection. The five framework integrations are registered explicitly (Publier warns at startup with a copy-paste list if any is missing — it never adds them for you):
import { defineConfig } from 'astro/config';import { docsShell } from '@publier/shell/integration';import expressiveCode from 'astro-expressive-code';import mdx from '@astrojs/mdx';import sitemap from '@astrojs/sitemap';import pagefind from 'astro-pagefind';import qwik from '@qwik.dev/astro';
export default defineConfig({ integrations: [ docsShell(), expressiveCode(), mdx(), sitemap(), pagefind(), qwik({ clientRouter: true }), ],});Order matters twice: docsShell() comes first — astro-expressive-code ≥0.43 registers into the Markdown processor it finds at its own setup, so Publier’s processor must already be in place (with it last, code fences silently render as plain <pre><code>) — and expressiveCode() comes before mdx() so its plugins slot into the MDX pipeline. This is the same array publier new scaffolds.
Wired by docsShell()
Every wire-up is idempotent — Publier detects existing config and backs off.
Disableable defaults (on by default):
Wired by docsShell() | Disable | Skipped when |
|---|---|---|
astro-mermaid (auto-detected) | docsShell({ mermaid: false }) | already in integrations[] or not installed |
prefetch (prefetchAll + viewport) | docsShell({ prefetch: false }) | astro.config.ts already sets prefetch: |
rehype-autolink-headings | docsShell({ autolinkHeadings: false }) | — |
rehype-external-links (target="_blank" on outbound links) | docsShell({ externalLinks: false }) | — |
Math (KaTeX, via remark-math + rehype-katex) | docsShell({ math: false }) | — |
| Search UI (Pagefind dialog + button) | docsShell({ search: false }) | — |
Opt-in features (off by default):
| Feature | Enable | Peer deps |
|---|---|---|
| Snippets | docsShell({ snippets: { directory: 'src/content/snippets' } }) | — |
Driven by publier.config.yaml (inert when the key is absent):
vars:— expands{{var}}placeholders inside MDX text.fonts:— emits Google Fonts links or@font-faceblocks plus--font-sans/--font-serif/--font-monooverrides.analytics:— injects provider snippets (GA4, PostHog, Plausible, Fathom, Umami) into<head>.sidebar.hidden: truein page frontmatter — excludes the page from the auto-generated sidebar.
Ordering
Astro runs integrations in array order. Keep docsShell() first: it pins the Markdown processor that later integrations register into — astro-expressive-code ≥0.43 detects the processor at its own setup, so registering it before docsShell() silently drops all code-fence processing (Publier warns at startup when it sees this). Keep expressiveCode() before mdx(). Markdown plugin arrays are concatenated — Publier’s plugins run first, then yours.
src/content.config.ts
Register your content collections. Publier ships loaders and schemas for each:
import { defineCollection } from 'astro:content';import { docsLoader, blogLoader, contentLoader } from '@publier/shell/loaders';import { docsSchema, blogSchema, changelogSchema } from '@publier/shell/schemas';
export const collections = { docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), blog: defineCollection({ loader: blogLoader(), schema: blogSchema }), changelog: defineCollection({ loader: contentLoader({ base: './src/content/changelog' }), schema: changelogSchema, }),};docsSchema() accepts an extend option for adding custom frontmatter fields. If you extend, note that Astro 7 bundles zod v4 (astro/zod — the z behind astro:content schemas), so zod-v3-only idioms in schema extensions need updating.
publier.config.yaml
Project-root YAML file. docsShell() reports malformed supported sections as build errors. publier doctor checks YAML syntax only; use a build to validate the framework configuration.
site: name: My Docs # site name (OG images, RSS, meta tags) url: https://docs.example.com # canonical URL for sitemaps
nav: default: links: - label: GitHub href: https://github.com/my-org/my-docs external: true
snippets: directory: src/content/snippets # reusable MDX fragments
search: enabled: true # show the header search trigger
llms: enabled: true # generate /llms.txt for the whole siteSee Global settings for the full field list.
theme.yaml
Pick a built-in preset, then optionally override individual tokens:
preset: maple # almond, aspen, catppuccin, dark, dusk, emerald, enterprise, light, # maple, neutral, ocean, purple, ruby, solar, vitepress
colors: primary: "oklch(65% 0.2 50)"See Theming for the full token reference.
meta.yaml (per folder)
The default documentation route reads section metadata from publier.config.yaml:
docs: sidebar: meta: guides: { label: Guides, order: 20 }Pages use sidebar.order frontmatter, with top-level order as the fallback. The nested field takes precedence from native 8.0.3.
For a custom docs route, readMetaYaml(basePath) from @publier/shell/search reads folder meta.yaml files into sidebar metadata. The custom route must merge that metadata and pass it to buildSidebar(). Creating the files alone does not change the default route.