---
title: "VitePress SEO Guide"
description: "VitePress offers built-in SEO features like sitemap generation, meta tags, and fast static site generation for documentation and blogs."
canonical_url: "https://nuxtseo.com/learn-seo/vue/ssr-frameworks/vitepress"
last_updated: "2025-12-17"
---

<key-takeaways>

- [VitePress](https://vitepress.dev) is ideal for documentation and blogs. fast static generation with built-in search
- Native sitemap generation with `sitemap.hostname` config option
- Static-only (no SSR). use Nuxt Content for dynamic features or authentication

</key-takeaways>

VitePress is a static site generator built on [Vite](https://vite.dev) and Vue 3, designed for documentation sites and content-heavy blogs. The initial visit serves pre-rendered HTML for [fast loading and optimal SEO](https://vitepress.dev/guide/what-is-vitepress), while subsequent navigation behaves like an SPA.

## When to Use VitePress

VitePress beats Nuxt Content when:

- Building technical documentation with minimal setup
- Speed and simplicity matter more than flexibility
- Content is 100% static (no authentication, no dynamic server features)
- You want [built-in search and code highlighting](https://vitepress.dev/guide/what-is-vitepress) without configuration

VitePress has [395,965 weekly npm downloads](https://www.vuemastery.com/blog/nuxt-vs-vitepress-vs-astro/) vs Nuxt Content's 74,690. Choose Nuxt Content when you need SSR, complex routing with non-markdown pages, or deeper integration with Nuxt modules.

## SEO Features

### Automatic Static HTML

VitePress pre-renders pages at build time, generating static HTML files. This approach [delivers excellent SEO while maintaining SPA benefits](https://soubiran.dev/series/create-a-blog-with-vitepress-and-vue-js-from-scratch/enhance-website-visibility-seo-metadata-and-sitemap) for user experience.

On PageSpeed Insights, VitePress sites achieve [near-perfect performance scores](https://vitepress.dev/guide/what-is-vitepress) even on low-end mobile devices. Google's Core Web Vitals directly impact rankings.

### Built-in Sitemap Generation

VitePress includes [native sitemap support](https://vitepress.dev/guide/sitemap-generation). Enable it in `.vitepress/config.ts`:

```ts [.vitepress/config.ts]
export default {
  sitemap: {
    hostname: 'https://mysite.com'
  }
}
```

This generates `sitemap.xml` in `.vitepress/dist` during build. For `<lastmod>` tags, enable the `lastUpdated` option:

```ts [.vitepress/config.ts]
export default {
  sitemap: {
    hostname: 'https://mysite.com'
  },
  lastUpdated: true
}
```

VitePress uses the [sitemap module](https://vitepress.dev/guide/sitemap-generation) under the hood. Pass any SitemapStream options directly to the `sitemap` config.

### Custom Sitemap Items

Use `transformItems` to [modify sitemap entries before writing](https://vitepress.dev/guide/sitemap-generation):

```ts [.vitepress/config.ts]
export default {
  sitemap: {
    hostname: 'https://mysite.com',
    transformItems: (items) => {
      // Filter out draft pages
      return items.filter(item => !item.url.includes('/drafts/'))
    }
  }
}
```

### Alternative: Build Hooks

For advanced use cases, use [VitePress build hooks](https://dev.to/paullaros/generating-a-dynamic-sitemap-with-vitepress-ldd) like `buildEnd` to generate custom sitemaps:

```ts [.vitepress/config.ts]
import { writeFileSync } from 'node:fs'
import { SitemapStream, streamToPromise } from 'sitemap'

export default {
  async buildEnd(siteConfig) {
    const sitemap = new SitemapStream({ hostname: 'https://mysite.com' })

    const pages = await generatePageList(siteConfig)
    pages.forEach(page => sitemap.write(page))

    sitemap.end()
    const data = await streamToPromise(sitemap)
    writeFileSync('.vitepress/dist/sitemap.xml', data.toString())
  }
}
```

## Meta Tags Configuration

### Site-Level Meta Tags

Add meta tags globally using the [`head` config](https://vitepress.dev/reference/site-config):

```ts [.vitepress/config.ts]
export default {
  head: [
    ['meta', { name: 'description', content: 'My documentation site' }],
    ['meta', { property: 'og:type', content: 'website' }],
    ['meta', { property: 'og:image', content: 'https://mysite.com/og.png' }],
    ['link', { rel: 'icon', href: '/favicon.ico' }]
  ]
}
```

User-added tags render before the closing `</head>` tag, [after VitePress's built-in tags](https://vitepress.dev/reference/site-config).

### Page-Level Meta Tags

Override meta tags per page using [frontmatter](https://vitepress.dev/reference/frontmatter-config):

```yaml
---
head:
  -
    - meta
    - name: description
      content: Custom description for this page
  -
    - meta
    - property: og:title
      content: Custom OG Title
  -
    - meta
    - name: keywords
      content: vitepress, seo, vue
---
```

Frontmatter meta tags [append after site-level tags](https://vitepress.dev/reference/frontmatter-config). Note that setting OG tags globally and overriding per-page can [cause duplicate tags in HTML output](https://github.com/vuejs/vitepress/issues/975).

### Dynamic Meta Tags

For dynamic meta tags, use [transform hooks](https://laros.io/adding-dynamic-meta-tags-to-vitepress):

```ts [.vitepress/config.ts]
export default {
  transformPageData(pageData) {
    pageData.frontmatter.head ??= []
    pageData.frontmatter.head.push([
      'meta',
      {
        property: 'og:title',
        content: pageData.frontmatter.layout === 'home'
          ? 'Homepage - My Site'
          : pageData.title
      }
    ])
  }
}
```

`transformPageData` runs during both dev and build. For build-only transforms, use [`transformHead`](https://olets.dev/posts/per-page-dynamic-social-metas-in-vitepress/), but note it doesn't run during development.

## Built-in Search

VitePress includes [fuzzy full-text search using minisearch](https://vitepress.dev/reference/default-theme-search). Enable local search in `.vitepress/config.ts`:

```ts [.vitepress/config.ts]
export default {
  themeConfig: {
    search: {
      provider: 'local'
    }
  }
}
```

No external service required. search runs in-browser using an indexed bundle.

### Algolia DocSearch

For larger sites, integrate [Algolia DocSearch](https://vitepress.dev/reference/default-theme-search):

```ts [.vitepress/config.ts]
export default {
  themeConfig: {
    search: {
      provider: 'algolia',
      options: {
        appId: 'YOUR_APP_ID',
        apiKey: 'YOUR_API_KEY',
        indexName: 'YOUR_INDEX_NAME'
      }
    }
  }
}
```

Algolia crawls your site and provides advanced search with typo tolerance and result ranking.

## Clean URLs

VitePress supports [clean URLs without `.HTML` extensions](https://github.com/vuejs/vitepress/discussions/548). Enable them in config:

```ts [.vitepress/config.ts]
export default {
  cleanUrls: true
}
```

Clean URLs avoid [duplicate content issues](https://github.com/vuejs/vitepress/discussions/548) where `/page` and `/page.html` are treated as separate URLs. This matters for sitemaps and canonical tags. [search engines mark mismatched URLs as duplicate content](https://github.com/vuejs/vitepress/discussions/548).

## VitePress vs Nuxt Content

<table>
<thead>
  <tr>
    <th>
      Feature
    </th>
    
    <th>
      VitePress
    </th>
    
    <th>
      Nuxt Content
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <strong>
        Build Speed
      </strong>
    </td>
    
    <td>
      <a href="https://www.vuemastery.com/blog/nuxt-vs-vitepress-vs-astro/" rel="nofollow">
        Blazing fast with Vite
      </a>
    </td>
    
    <td>
      Slower with larger sites
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Use Case
      </strong>
    </td>
    
    <td>
      <a href="https://vitepress.dev/guide/what-is-vitepress" rel="nofollow">
        Documentation, blogs, static content
      </a>
    </td>
    
    <td>
      Full web apps with markdown
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        SSR
      </strong>
    </td>
    
    <td>
      Static-only
    </td>
    
    <td>
      Full SSR + SSG
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Search
      </strong>
    </td>
    
    <td>
      Built-in local search
    </td>
    
    <td>
      Requires integration
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Learning Curve
      </strong>
    </td>
    
    <td>
      <a href="https://www.vuemastery.com/blog/nuxt-vs-vitepress-vs-astro/" rel="nofollow">
        Simpler, minimalistic
      </a>
    </td>
    
    <td>
      <a href="https://www.vuemastery.com/blog/nuxt-vs-vitepress-vs-astro/" rel="nofollow">
        Steeper, feature-rich
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Page Directory
      </strong>
    </td>
    
    <td>
      Markdown only
    </td>
    
    <td>
      <a href="https://github.com/vuejs/vitepress/discussions/3785" rel="nofollow">
        Mixes markdown + Vue pages
      </a>
      
       (with friction)
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Ecosystem
      </strong>
    </td>
    
    <td>
      Growing, documentation-focused
    </td>
    
    <td>
      <a href="https://www.vuemastery.com/blog/nuxt-vs-vitepress-vs-astro/" rel="nofollow">
        Larger, mature module system
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Authentication
      </strong>
    </td>
    
    <td>
      <a href="https://github.com/vuejs/vitepress/discussions/548" rel="nofollow">
        Doesn't fit SSG model
      </a>
    </td>
    
    <td>
      Supported with SSR
    </td>
  </tr>
</tbody>
</table>

VitePress [excels for performance-critical static sites](https://www.vuemastery.com/blog/nuxt-vs-vitepress-vs-astro/) where all content is known at build time. Nuxt Content handles [complex routing, dynamic content, and SSR requirements](https://www.vuemastery.com/blog/nuxt-vs-vitepress-vs-astro/) better.

## Limitations

- **No SSR**: All content generates at build time. Dynamic features like user authentication [don't fit VitePress](https://github.com/vuejs/vitepress/discussions/548).
- **Static Content Only**: Pages requiring server-side data fetching need Nuxt or custom Vite SSR.
- **Smaller Ecosystem**: [Fewer plugins compared to Nuxt](https://www.vuemastery.com/blog/nuxt-vs-vitepress-vs-astro/), though actively growing.
- **Mixed Routing Challenges**: [Integrating VitePress within existing Nuxt projects](https://github.com/vuejs/vitepress/discussions/3785) causes routing conflicts. better to run as separate sites.

## Using Nuxt?

Nuxt offers deeper SEO integration through [@nuxtjs/seo](/learn-seo/nuxt/mastering-meta/introduction), which handles sitemaps, robots.txt, structured data, and OG images with zero configuration.

[Learn more about Nuxt Content for documentation →](https://content.nuxt.com/)
