Site Config
Site config is where you can define the global settings of the site. App config options define settings that apply to every VitePress site, regardless of what theme it is using. For example, the base directory or the title of the site.
Overview
Config Resolution
The config file is always resolved from <root>/.vitepress/config.[ext]
, where <root>
is your VitePress project root, and [ext]
is one of the supported file extensions. TypeScript is supported out of the box. Supported extensions include .js
, .ts
, .mjs
, and .mts
.
It is recommended to use ES modules syntax in config files. The config file should default export an object:
export default {
// app level config options
lang: 'en-US',
title: 'VitePress',
description: 'Vite & Vue powered static site generator.',
...
}
Config Intellisense
Using the defineConfig
helper will provide TypeScript-powered intellisense for config options. Assuming your IDE supports it, this should work in both JavaScript and TypeScript.
import { defineConfig } from 'vitepress'
export default defineConfig({
// ...
})
VitePress also directly supports TS config files. You can use .vitepress/config.ts
with the defineConfig
helper as well.
Conditional Config
If you need to conditionally configure based on the command (serve
or build
), the mode being used, or if it's a SSR build, you can export a function instead:
export default async ({ command, mode, isSsrBuild }) => {
if (command === 'serve') {
return {
// dev specific config
}
} else {
// build specific config
return {
// ...
}
}
}
Async Config
If your config needs to call async APIs, you can export an async function instead. But make sure to use dynamic import for CJS modules:
export default async () => {
const posts = await (await fetch('https://jsonplaceholder.typicode.com/posts')).json()
return {
// site config
themeConfig: {
posts
}
}
}
App Config
appearance
- Type:
boolean | 'dark' | 'force-dark' | import('@vueuse/core').UseDarkOptions
- Default:
true
Whether to enable dark mode (by adding the .dark
class to the <html>
element).
- If the option is set to
true
, the default theme will be determined by the user's preferred color scheme. - If the option is set to
dark
, the theme will be dark by default, unless the user manually switches it. - If the option is set to
false
, users will not be able to toggle the theme.
This option injects an inline script that restores users settings from local storage using the vitepress-theme-appearance
key. This ensures the .dark
class is applied before the page is rendered to avoid flickering.
export default {
appearance: 'dark' // or false or true
}
base
- Type:
string
- Default:
/
The base URL the site will be deployed at. You will need to set this if you plan to deploy your site under a sub path, for example, GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/
, then you should set base to '/bar/'
. It should always start and end with a slash.
The base is automatically prepended to all the URLs that start with / in other options, so you only need to specify it once.
export default {
base: '/base/'
}
cleanUrls
- Type:
boolean
- Default:
false
When set to true
, VitePress will remove the trailing .html
from URLs. Also see Generating Clean URL.
Server Support Required
Enabling this may require additional configuration on your hosting platform. For it to work, your server must be able to serve /foo
when visiting /foo.html
without a redirect.
description
- Type:
string
- Default:
A VitePress Site
Description for the site. This will render as a <meta>
tag in the page HTML.
export default {
description: 'A VitePress Site'
}
head
- Type:
HeadConfig[]
- Default:
[]
Additional elements to render in the <head>
tag in the page HTML. The user-added tags are rendered before the closing head
tag, after VitePress tags.
type HeadConfig =
| [string, Record<string, string>]
| [string, Record<string, string>, string]
Example: Adding a favicon
export default {
head: [['link', { rel: 'icon', href: '/favicon.ico' }]]
} // put favicon.ico in public directory, if base is set, use /base/favicon.ico
/* Would render:
<link rel="icon" href="/favicon.ico">
*/
Example: Adding Google Fonts
export default {
head: [
[
'link',
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' }
],
[
'link',
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }
],
[
'link',
{ href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }
]
]
}
/* Would render:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
*/
Example: Registering a service worker
export default {
head: [
[
'script',
{ id: 'register-sw' },
`;(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
})()`
]
]
}
/* Would render:
<script id="register-sw">
;(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
})()
</script>
*/
Example: Using Google Analytics
export default {
head: [
[
'script',
{ async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }
],
[
'script',
{},
`window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'TAG_ID');`
]
]
}
/* Would render:
<script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'TAG_ID');
</script>
*/
ignoreDeadLinks
- Type:
boolean | 'localhostLinks' | (string | RegExp | ((link: string) => boolean))[]
- Default:
false
When set to true
, VitePress will not fail builds due to dead links.
When set to 'localhostLinks'
, the build will fail on dead links, but won't check localhost
links.
export default {
ignoreDeadLinks: true
}
It can also be an array of exact url string, regex patterns, or custom filter functions.
export default {
ignoreDeadLinks: [
// ignore exact url "/playground"
'/playground',
// ignore all localhost links
/^https?:\/\/localhost/,
// ignore all links include "/repl/""
/\/repl\//,
// custom function, ignore all links include "ignore"
(url) => {
return url.toLowerCase().includes('ignore')
}
]
}
lang
- Type:
string
- Default:
en-US
The lang attribute for the site. This will render as a <html lang="en-US">
tag in the page HTML.
export default {
lang: 'en-US'
}
lastUpdated
- Type:
boolean
- Default:
false
Use git commit to get the timestamp. This option enables the default theme to display the page's last updated time. You can customize the text via themeConfig.lastUpdatedText
option.
export default {
lastUpdated: true
}
markdown
- Type:
MarkdownOption
Configure Markdown parser options. VitePress uses Markdown-it as the parser, and Shiki to highlight language syntax. Inside this option, you may pass various Markdown related options to fit your needs.
export default {
markdown: {
theme: 'material-theme-palenight',
lineNumbers: true,
// adjust how header anchors are generated,
// useful for integrating with tools that use different conventions
anchor: {
slugify(str) {
return encodeURIComponent(str.toLowerCase().replace(/\s+/g, '-'))
}
}
}
}
Below are all the options that you can have in this object. Check out type declarations and jsdocs for all the available options.
interface MarkdownOptions extends MarkdownIt.Options {
// Custom theme for syntax highlighting.
// You can use an existing theme.
// See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#all-themes
// Or add your own theme.
// See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#loading-theme
theme?:
| Shiki.IThemeRegistration
| { light: Shiki.IThemeRegistration; dark: Shiki.IThemeRegistration }
// Enable line numbers in code blocks.
lineNumbers?: boolean
// markdown-it-anchor plugin options.
// See: https://github.com/valeriangalliat/markdown-it-anchor#usage
anchor?: anchorPlugin.AnchorOptions
// markdown-it-attrs plugin options.
// See: https://github.com/arve0/markdown-it-attrs
attrs?: {
leftDelimiter?: string
rightDelimiter?: string
allowedAttributes?: string[]
disable?: boolean
}
// specify default language for syntax highlighter
defaultHighlightLang?: string
// markdown-it-toc-done-right plugin options.
// See: https://github.com/nagaozen/markdown-it-toc-done-right
toc?: any
// Configure the Markdown-it instance.
config?: (md: MarkdownIt) => void
}
mpa
- Type:
boolean
- Default:
false
When set to true
, the production app will be built in MPA Mode. MPA mode ships 0kb JavaScript by default, at the cost of disabling client-side navigation and requires explicit opt-in for interactivity.
outDir
- Type:
string
- Default:
./.vitepress/dist
The build output location for the site, relative to project root.
export default {
outDir: '../public'
}
rewrites
- Type:
Record<string, string>
Define custom directory <-> URL mappings. See Routing: Route Rewrites for more details.
export default {
rewrites: {
'source/:page': 'destination/:page'
}
}
sitemap
- Type:
SitemapConfig
Generate sitemap.xml with all pages.
export default {
sitemap: {
hostname: 'https://example.com'
}
}
export interface SitemapConfig {
hostname: string
transformItems?: (items: SitemapItem[]) => Awaitable<SitemapItem[]>
}
srcDir
- Type:
string
- Default:
.
The directory where your markdown pages are stored, relative to project root. Also see Root and Source Directory.
export default {
srcDir: './src'
}
srcExclude
- Type:
string
- Default:
undefined
A glob pattern for matching markdown files that should be excluded as source content.
export default {
srcExclude: ['**/README.md', '**/TODO.md']
}
title
- Type:
string
- Default:
VitePress
Title for the site. When using the default theme, this will be displayed in the nav bar.
Also, it will be used as the default suffix for all individual page titles, unless titleTemplate
is defined. An individual page's final title will be <title> | <siteTitle>
, where <title>
is the first # header
of the page. For example, with the following config and page content:
export default {
title: 'My Awesome Site'
}
# Hello
The title of the page will be Hello | My Awesome Site
.
titleTemplate
- Type:
string | boolean
Allows customizing each page's title suffix or the entire title. For example:
export default {
title: 'My Awesome Site',
titleTemplate: 'Custom Suffix'
}
# Hello
The title of the page will be Hello | Custom Suffix
.
To completely customize how the title should be rendered, you can use the :title
symbol in titleTemplate
:
export default {
titleTemplate: ':title - Custom Suffix'
}
Here :title
will be replaced with the text inferred from the page's first # header
. The title of the previous example page will be Hello - Custom Suffix
.
The option can be set to false
to disable title suffixes.
transformHead
- Type:
(context: TransformContext) => Awaitable<HeadConfig[]>
The transformHead
hook allows you to transform the head before generating each page. It will receive the context object that includes the page path, route, and metadata. This can be used to generate dynamic meta tags, for example:
export default {
async transformHead(context) {
// ...
}
}
interface TransformContext {
page: string // e.g. index.md (relative to srcDir)
assets: string[] // all non-js/css assets as fully resolved public URLs
siteConfig: SiteConfig
siteData: SiteData
pageData: PageData
title: string
description: string
head: HeadConfig[]
content: string
}
Note that this hook is only called when generating the site statically. It is not called during dev. If you need to add dynamic head entries during dev, you can use the transformPageData
hook instead:
export default {
transformPageData(pageData) {
pageData.frontmatter.head ??= []
pageData.frontmatter.head.push([
'meta',
{
name: 'og:title',
content:
pageData.frontmatter.layout === 'home'
? `VitePress`
: `${pageData.title} | VitePress`
}
])
}
}
Example: Adding a canonical URL <link>
export default {
transformHead({ assets, head, pageData }) {
// only add preload links for css and js assets
head.push([
'link',
{
rel: 'canonical',
href: `https://example.com/${pageData.relativePath.replace(/index\.md$/, '').replace(/\.md$/, '.html')}`
}
])
}
}
transformHtml
- Type:
(code: string, id: string, context: TransformContext) => Awaitable<string | void>
The transformHtml
hook allows you to transform the content of each page before saving to disk.
export default {
async transformHtml(code, id, context) {
// ...
}
}
transformPageData
- Type:
(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>
The transformPageData
hook allows you to transform the pageData
of each page. You can directly mutate pageData
or return changed values which will be merged into the page data.
export default {
async transformPageData(pageData, { siteConfig }) {
pageData.contributors = await getPageContributors(pageData.relativePath)
}
// or return data to be merged
async transformPageData(pageData, { siteConfig }) {
return {
contributors: await getPageContributors(pageData.relativePath)
}
}
}
interface TransformPageContext {
siteConfig: SiteConfig
}
vite
- Type:
import('vite').UserConfig
Pass raw Vite config to internal Vite dev server / bundler.
export default {
vite: {
// Vite config options
}
}
vue
- Type:
import('@vitejs/plugin-vue').Options
Pass raw @vitejs/plugin-vue
options to the internal plugin instance.
export default {
vue: {
// @vitejs/plugin-vue options
}
}