Public configuration lives in site.config.mjs. Astro refreshes the development site after changes to names, origins, or navigation. The outer defineSiteConfig() call adds completion, fills safe defaults for omitted optional sections, and reports invalid origins, paths, and pagination values at startup.
Post covers
siteConfig.postCover sets the default post-cover layout: left, right, odd-left, odd-right, or top. A post can override the layout, ratio, side width, and compact mode in frontmatter:
cover: /img/cover.webp
coverStyle:
layout: right
ratio: 4/3
width: 240
compact: false
siteConfig.profile accepts avatar (plus the legacy url alias), name, description, circle, location, organization, and layout: 'left' | 'right'. Mobile pages reuse the same profile in the bottom sheet with taxonomy navigation. Plume's deprecated top-level or locale avatar: { ... } form also falls back to profile.
Set profile to false to remove the desktop card. As in Plume, a horizontal Tags/Categories/Archives navigation then appears above the post list, while mobile keeps those links in the extract sheet.
Side covers automatically move above the post on mobile, matching Plume.
Page transitions
transition.page applies a Plume-compatible content transition during full-page navigation: fade-slide-y leaves first, then enters, without taking a whole-page browser snapshot that can flash the wrong theme. Documentation sidebar links preserve the shared shell and replace only the document content, while Blog, Tags, Categories, and Archives preserve the header and profile card. Page scripts are re-initialized after each partial update. prefers-reduced-motion disables the animation. Set transition: false to disable all transitions or transition.page: false to disable only full-page navigation.
Appearance
appearance matches Plume and defaults to true, following the system color preference until the user makes a stored choice. Use 'dark' for a dark default when no choice is stored, false to force light mode and hide every appearance switch, or 'force-dark' to force dark mode and hide the switches. A locale-level value overrides the global setting.
transition.appearance accepts fade, circle-clip, horizontal-clip, vertical-clip, skew-clip, blinds-vertical, blinds-horizontal, soft-blur-fade, and diamond-reveal. Set it to false, or enable reduced motion at the OS level, to switch immediately without a View Transition. Dark pages temporarily print in light mode and restore their prior appearance afterwards.
Locales
locales accepts any number of languages. Each locale uses home as its route prefix; place content under the matching directory or set lang explicitly in frontmatter. The framework generates blog, tag, category, archive, pagination-data, LLM-document, and SEO-alternate routes for every configured locale, while the language menu only lists translations that actually exist.
The frozen Plume presets for Simplified Chinese, Traditional Chinese, English, German, French, Russian, Japanese, and Korean are built in, including their short and regional language codes. Site identity, descriptions, and navigation remain locale configuration fields, and an explicitly configured label overrides its preset.
Navbar
Each locale's canonical navbar field accepts Plume string links and { text, link, icon, badge, activeMatch, prefix, items, target, rel, noIcon }; the old navigation field remains an alias. The legacy label and href names also remain supported. An internal string link inherits the target page's title, icon, and badge. prefix recursively resolves relative child links, with up to two visible dropdown levels. When omitted, Home, Posts, Tags, and Archives are generated from the locale's first Post collection.
navbar: [
'/docs/',
{ text: 'Blog', link: '/blog/', activeMatch: '^/(blog|article)/', icon: 'material-symbols:article-outline' },
{
text: 'Guide',
prefix: '/docs/guide/',
items: [
{ text: 'Configuration', link: 'configuration/', badge: { text: 'New', type: 'warning' } },
{ text: 'Astro', link: 'https://astro.build/', icon: 'simple-icons:astro' },
],
},
]
External links open in a new window and show the external-link marker by default; set noIcon: true to hide it. Navbar icons share the Markdown icon provider and support Iconify, IconFont, Font Awesome, image URLs, and { svg }.
Global options provide defaults and object-valued locale options are shallow-merged over them. A locale may independently override logo, logoDark, profile, social, navbarSocialInclude, appearance, transition, footer, outline, aside, externalLinkIcon, and createTime without inheriting another locale's navbar or labels. Use navbar: false in page frontmatter to hide the navbar on that page.
Page and content options
pageLayout supports home, posts, doc, page, friends, custom, false, and custom component names. A posts page may select a Post collection with collection; page keeps the standalone body; custom/false output only the Markdown body. Put named layouts in theme/components/layouts/; the filename is the layout name.
Global, locale, and page-level outline and aside values control the content outline. externalLinkIcon is enabled by default and can be disabled per page; the old externalLink name remains compatible. createTime: 'only-posts' limits creation dates to posts and post lists, while false hides them everywhere. Set plugins.nprogress: false to disable the top progress bar during internal navigation.
Layout slots
Add an .astro or .vue file named after a Plume slot under theme/components/slots/, for example doc-top.astro or DocTop.astro. Components receive the currently available lang, route, entry, layout, and posts props. A missing component produces no extra DOM.
Supported names include:
- General:
layout-top,layout-bottom,custom-content,footer-content,bulletin-content, andnot-found. - Navigation: every
nav-bar-*-before/afterandnav-screen-*-before/afterslot from Plume. - Documents and pages:
page-top/bottom,doc-top/bottom,doc-before/after,doc-content-before,doc-footer-before, alldoc-title-*anddoc-meta-*positions,sidebar-nav-before/after,aside-top/bottom, andaside-outline-before/after. - Posts:
posts-top/bottom,posts-aside-top/bottom,posts-extract-before/after, everyposts-post-list-*hook, plus all tag, category, and archive positions.
The legacy FooterContent.astro and BulletinContent.astro overrides remain compatible; a same-named slot component takes precedence.
Automatic frontmatter
autoFrontmatter is enabled by default. Before development, checks, or builds, a new Markdown file receives a filename-derived title, filesystem createTime, and random eight-character permalink only when those fields are missing; the result is written back to the source as in Plume. Use { permalink: 'filepath' } for stable path-derived URLs. When the optional pinyin-pro package is installed, Chinese paths are transliterated.
Global and collection-level options can independently disable title, createTime, or permalink, and may provide a synchronous or asynchronous transform(data, context, locale). context contains filepath, relativePath, and body content; collection settings take precedence. Set autoFrontmatter: false to disable source write-back entirely.
Pagination
siteConfig.pagination accepts false, a page size, or { perPage: number }. Both the starter and Plume default to 15 posts per page.
siteConfig.categoriesExpand controls the initially expanded category depth and accepts a number or 'deep'. Directory names may use an 01.Name prefix for ordering; the prefix stays hidden while every category level remains available in the category page and post breadcrumbs.
siteConfig.tagsTheme accepts 'colored', 'gray', or 'brand'; colored mode uses Plume's complete 18-color preset. siteConfig.meta independently controls tags, readingTime, wordCount, and createTime, with 'short' and 'long' date formats. A page may set readingTime: false to hide its reading statistics.
siteConfig.readingTime matches Plume's reading-time plugin and accepts false, wordPerMinute, and locales keyed by locale path. Each locale may override word with $word, time with $time, and less1Minute; otherwise the frozen Chinese, English, Traditional Chinese, German, French, Russian, Japanese, and Korean presets are used.
Post and doc collections
Each locale accepts any number of Plume-style collections. dir is relative to that locale's content directory:
locales: {
'en-US': {
home: '/en/',
collections: [
{ type: 'post', dir: 'blog', title: 'Blog' },
{ type: 'post', dir: 'news', title: 'News', link: '/updates/' },
{ type: 'doc', dir: 'docs', title: 'Docs', sidebar: 'auto' },
],
},
},
Post collections support include, exclude, pagination, postList, link, linkPrefix, independent tag/category/archive switches, paths and labels, plus collection-level tagsTheme, meta, postCover, profile, social, categoriesExpand, and categoriesTransform. Generated pages, breadcrumbs, pagination JSON, sitemap entries, and language switching use the resolved collection routes.
When migrating an older Plume site, deprecated top-level blog, article, and notes settings plus locale-level notes are converted into collections at startup; a non-empty collections array at the target level takes precedence. Legacy profile.url is also normalized to profile.avatar globally, per locale, and in Post collections. These aliases are migration aids only; new configuration should use collections and profile.avatar directly.
Doc collections support recursive directory and numeric-prefix navigation through sidebar: 'auto'; sidebarCollapsed controls initial group state and sidebarScrollbar controls the scrollbar. A manual array accepts strings or { text, link, prefix, icon, badge, collapsed, items }, including scoped items: 'auto' and link: '---' separators.
Plume's global multi-sidebar form is also supported: sidebar: { '/docs/': 'auto', '/guide/': [...] }, with longest-prefix matching. A value may also use { items, prefix }; page frontmatter can force a configured sidebar with sidebar: '/guide/' or disable it with sidebar: false. Sidebar items retain the legacy dir alias plus target and rel.
site.config.mjs already imports defineSiteConfig from ./theme/config.mjs. It preserves the supplied object reference while filling defaults required by the theme runtime. Theme integrations may also use defineThemeConfig, defineNavbarConfig, defineCollections, and defineCollection from theme/node.ts; the other helpers still return their input unchanged.
Legacy Plume options under plugins.copyCode, plugins.shiki, plugins.readingTime, plugins.comment, plugins.watermark, plugins.replaceAssets, plugins.llmstxt, plugins.markdownPower, plugins.markdownChart, plugins.markdownImage, plugins.markdownInclude, plugins.markdownMath, plugins.search, and plugins.docsearch fall back to their flat equivalents. Flat or markdown options win when both forms exist. markdown.image supports Plume's complete figure, lazyload, mark, size, legacySize, and obsidianSize option set; codeHighlighter: false falls back to plain fenced code. plugins.markdownPower: false disables only that enhancement group, leaving image, math, include, hint, and chart features under their own switches.
The plugins.seo object supports Plume's hostname, author, restrictions, autoDescription, fallBackImage, twitterID, isArticle, ogp, jsonLd, customHead, and canonical; false disables generated Open Graph, Twitter Card, and JSON-LD data. Twitter/X handles are resolved from social first, with twitterID kept only as a compatibility fallback. plugins.sitemap supports hostname, extraUrls, excludePaths, sitemapFilename, sitemapXSLFilename, sitemapXSLTemplate, changefreq, modifyTimeGetter, devServer, devHostname, and xmlNameSpace; false removes sitemap output and its robots.txt entry.
Local search uses Pagefind. plugins.search.isSearchable(page) controls indexing, while disableQueryPersistence and locales remain effective. Plume's miniSearch tokenizer options have no Pagefind equivalent, so their types are retained for migration but they do not alter Pagefind tokenization. Plume's top-level cache and configFile options control VuePress compilation caching and configuration loading; Astro has no matching runtime stage, so these fields are type-only migration shims and should be removed from migrated configuration.
Trusted chart scripts
As in Plume, chartjs, echarts, flowchart, markmap, plantuml, and mermaid are disabled by default and enabled independently under markdown. plantuml may instead be an array of @mdit/plugin-plantuml options to limit syntax, change the server, or select an output format. This starter explicitly enables all six for its showcase.
js and javascript configurations for Chart.js and ECharts are disabled by default. Enable script execution and allowlist each trusted Markdown file only when you control its contents:
markdown: {
DANGEROUS_ALLOW_SCRIPT_EXECUTION: true,
DANGEROUS_SCRIPT_EXECUTION_ALLOWLIST: ['docs/guide/chart-demo.md'],
}
The allowlist also accepts '*', but that is not recommended for sites containing user content. Prefer json for ordinary charts.
Media embeds
As in Plume, acfun, bilibili, youtube, pdf, audioReader, and artPlayer are disabled by default and enabled independently under markdown. This starter explicitly enables all six for its showcase. Obsidian PDF and video embeds also depend on pdf and artPlayer, respectively.
markdown: {
youtube: true,
pdf: { pdfjsUrl: 'https://static.pengzhanbo.cn/pdfjs/' },
audioReader: true,
artPlayer: true,
}
Desktop browsers embed PDFs directly, while mobile browsers lazily load PDF.js. pdfjsUrl must point to a PDF.js distribution containing web/viewer.html. ArtPlayer supports Plume's MP4, MP3, WebM, Ogg, DASH, HLS, TS, FLV, MKV, MOV, and OGV types.
Markdown icons
Content uses Plume's ::name =size /color:: syntax, for example ::mdi:home =24 /#336f87::. Iconify embeds icons from installed collections and lazily loads other collections from the official Iconify API in the browser. The legacy :[name size/color]: form remains compatible.
markdown: {
icon: { provider: 'iconify', prefix: 'mdi' },
}
Set provider to iconfont or fontawesome and use assets for one or more .css / .js URLs. Font Awesome also accepts the built-ins fontawesome and fontawesome-with-brands, while ::fontawesome fas:house 2xl:: overrides the provider for one icon.
markdown.repl independently enables go, kotlin, rust, and python. The first three submit code to Plume's public playground services; Python lazily loads Pyodide and executes locally in the browser. Run only trusted, lightweight examples.
Social links and footer
social uses Plume's array shape and accepts built-in Simple Icons names, the twitter / weibo compatibility aliases, and custom SVG. navbarSocialInclude filters only the desktop navbar and its extra menu; mobile navigation and the blog profile retain the full list.
social: [
{ icon: 'github', link: 'https://github.com/example' },
{ icon: 'weibo', link: 'https://weibo.com/example', ariaLabel: 'Weibo' },
{ icon: { svg: '<svg>...</svg>', name: 'custom' }, link: 'https://example.com' },
],
navbarSocialInclude: ['github', 'weibo'],
footer: {
message: 'Power by <a href="https://astro.build/">Astro</a>',
copyright: 'Copyright © 2026 Example',
},
Set the global footer to false to hide it site-wide, or use footer: false in page frontmatter to hide it only on that page.
Friends pages
Set pageLayout: friends in frontmatter (the legacy friends: true also works) to enable Plume's friends layout. cols controls the desktop column limit and contentPosition places Markdown before or after the lists. Both list and groups support avatars, descriptions, location, organization, social links, and separate light/dark colors. See /en/friends/ for a complete example.
Bulletin
bulletin supports the top-left, top-right, bottom-left, bottom-right, and center positions plus the always, session, and once dismissal lifetimes. enablePage accepts a boolean or a function receiving { path }; when id is omitted, the theme derives a stable identifier from the configuration. The starter bulletin appears only on /landing/.
Search providers
llmstxt: true generates /llms.txt, /llms-full.txt, each page's Plume-style index.md, the legacy /raw/ route, and the page-context menu beside document titles. As in Plume, the feature defaults to disabled; false removes the files and menu together, while page frontmatter llmstxt: false excludes only that page. Object form supports llmsTxt, llmsFullTxt, llmsPageTxt, stripHTML, locale, domain, linkExtension, filter, transformMarkdown, llmsTxtTemplate, and llmsTxtTemplateGetter; locale defaults to the root locale and must be set to 'all' for every language. plugins.llmstxt remains an alias, though the top-level field is preferred.
The default Pagefind index is generated at build time and needs no external service:
search: {
provider: 'local',
locales: {
'/en/': { placeholder: 'Search documentation' },
},
}
Local-search locales may override placeholder, buttonText, resetButtonTitle, backButtonTitle, noResultsText, and the footer keyboard labels; omitted values use the same presets as Plume.
Large documentation sites can switch to the same Algolia DocSearch adapter used by Plume. Its client and stylesheet load only when this provider is selected, and the adapter adds the current language as a lang facet:
search: {
provider: 'algolia',
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_API_KEY',
indexName: 'YOUR_INDEX_NAME',
locales: {
'/en/': { placeholder: 'Search documentation' },
},
}
The adapter also accepts DocSearch indices, searchParameters, translations, keyboardShortcuts, and indexBase. apiKey must be a public search-only key, never an admin key.
Asset URL replacement
replaceAssets is disabled by default. A production build can rewrite images under /images/ and video, audio, subtitle, or PDF URLs under /medias/ to a CDN without modifying the source Markdown, HTML, CSS, or JavaScript files:
replaceAssets: process.env.NODE_ENV === 'production'
? { image: 'https://images.example.com', media: 'https://media.example.com' }
: false,
A string or function replaces every built-in asset type. { find, replacement }, rule arrays, and a rules property provide custom matching. A string find beginning with ^ or ending with $ is treated as a regular expression; other strings match the start or end of a URL. As in Plume, built-in rules only recognize known extensions under /images/ and /medias/.
Build-time image dimensions
markdown.imageSize is disabled by default. Set it to true or 'local' to read local images during production builds and add intrinsic width and height attributes to content images; use 'all' to inspect remote images too. The legacy plugins.markdownPower.imageSize form remains supported:
markdown: {
imageSize: 'local',
},
Existing dimensions are preserved, and a single missing dimension is derived from the original ratio. Only built output changes; Markdown sources remain untouched. Remote mode adds network work and waits up to three seconds for each unreadable URL, so prefer local mode unless remote sizing is required.
Content encryption
Like Plume, encrypt supports a site-wide gate, administrator passwords, and page rules matched by Markdown file, directory, request path, or regular expression. A password may be one string or an array; unlocking a shared directory or rule remains valid for the current session:
encrypt: {
global: false,
admin: ['REPLACE_WITH_ADMIN_PASSWORD'],
rules: {
'notes/private/': 'directory-password',
'/private/': ['reader-password', 'editor-password'],
'^/(?:en/)?members/': 'member-password',
},
},
Individual pages still accept password and passwordHint in frontmatter. A partial ::: encrypt container accepts either its own password or an administrator password. Page and partial content use PBKDF2 and AES-GCM at build time, but a static-site gate is not a substitute for server-side access control; do not ship sensitive data in a public build. Replace or remove every demonstration password before using the theme for real content.
Git contributors and changelog
Production builds derive each Markdown page's last-updated time and contributors from Git history. Development skips git log by default. Contributors appear as inline names by default, or as an in-content block with avatars and links. As in Plume, the changelog is disabled by default:
lastUpdated: { formatOptions: { dateStyle: 'short', timeStyle: 'short' } },
contributors: {
mode: 'block', // or 'inline'
info: [
{ username: 'octocat', name: 'Site author', alias: 'Local Git Name' },
],
},
changelog: {
maxCount: 10,
repoUrl: 'https://github.com/owner/repo',
},
Frontmatter can disable one page with contributors: false, changelog: false, or lastUpdated: false; contributors: [extra contributor] supplements the generated list. gitInclude adds related files from the same repository to the page history. Set plugins: { git: true } when testing in development. CI must fetch complete history (fetch-depth: 0 in GitHub Actions). Missing Git, shallow history, and untracked files degrade to no metadata without failing the build.
Comment providers
Set features.comments to true, then choose Giscus, Waline, Twikoo, or Artalk in comment.provider. All four clients load on demand and use Plume's server fields:
comment: {
provider: 'Giscus',
repo: 'owner/repo',
repoId: 'R_...',
category: 'General',
categoryId: 'DIC_...',
// inputPosition: 'top',
// strict: true,
},
Waline uses serverURL, Twikoo uses envId, and Artalk uses server. Set comments: false in page frontmatter to disable comments on one page. Password-protected posts load comments only after a successful unlock.
Project structure
ermaozi
blog
docs
en
img
components
lib
pages
styles
astro.config.mjs
site.config.mjs
package.json
Use icon="simple" on a file-tree container or fence for generic file/folder icons. The default colored mode selects local VS Code icons by folder name and file type; set the global default with markdown.fileTree.icon.
Page fields
| Field | Purpose | Required |
|---|---|---|
title |
Page title | Yes |
description |
Search and SEO summary | Yes |
type |
post, doc, or page |
No |
order |
Documentation order | No |
group |
Documentation group | No |
cover / coverStyle |
Post cover and per-post cover layout | No |
Without a permalink, the theme derives a stable route from the file path. Set one explicitly when the URL must remain unchanged long term.
Copyright
Copyright Ownership:
This article link:https://astro.ermao.net/en/docs/guide/configuration/
License under:Attribution 4.0 International (CC-BY-4.0)