Skip to content

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:

js
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.

js
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:

js
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:

js
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.

js
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.

js
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.

js
export default {
  description: 'A VitePress Site'
}
  • 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.

ts
type HeadConfig =
  | [string, Record<string, string>]
  | [string, Record<string, string>, string]

Example: Adding a favicon

js
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

js
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

js
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

js
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>
*/
  • 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.

js
export default {
  ignoreDeadLinks: true
}

It can also be an array of exact url string, regex patterns, or custom filter functions.

js
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.

js
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.

js
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.

js
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.

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

js
export default {
  outDir: '../public'
}

rewrites

  • Type: Record<string, string>

Define custom directory <-> URL mappings. See Routing: Route Rewrites for more details.

js
export default {
  rewrites: {
    'source/:page': 'destination/:page'
  }
}

sitemap

  • Type: SitemapConfig

Generate sitemap.xml with all pages.

js
export default {
  sitemap: {
    hostname: 'https://example.com'
  }
}
ts
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.

js
export default {
  srcDir: './src'
}

srcExclude

  • Type: string
  • Default: undefined

A glob pattern for matching markdown files that should be excluded as source content.

js
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:

js
export default {
  title: 'My Awesome Site'
}
md
# 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:

js
export default {
  title: 'My Awesome Site',
  titleTemplate: 'Custom Suffix'
}
md
# 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:

js
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:

js
export default {
  async transformHead(context) {
    // ...
  }
}
ts
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:

js
export default {
  transformPageData(pageData) {
    pageData.frontmatter.head ??= []
    pageData.frontmatter.head.push([
      'meta',
      {
        name: 'og:title',
        content:
          pageData.frontmatter.layout === 'home'
            ? `VitePress`
            : `${pageData.title} | VitePress`
      }
    ])
  }
}
js
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.

js
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.

js
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)
    }
  }
}
ts
interface TransformPageContext {
  siteConfig: SiteConfig
}

vite

  • Type: import('vite').UserConfig

Pass raw Vite config to internal Vite dev server / bundler.

js
export default {
  vite: {
    // Vite config options
  }
}

vue

  • Type: import('@vitejs/plugin-vue').Options

Pass raw @vitejs/plugin-vue options to the internal plugin instance.

js
export default {
  vue: {
    // @vitejs/plugin-vue options
  }
}

VitePress Development Guide