VitePress SEO Guide · Nuxt SEO

-
-
-
-

[1.4K](https://github.com/harlan-zw/nuxt-seo)

[Nuxt SEO on GitHub](https://github.com/harlan-zw/nuxt-seo)

Learn SEO

Master search optimization

Nuxt

 Vue

-
-
-
-
-
-
-

-
-
-
-
-
-
-

-
-
-

-
-
-
-
-
-
-
-
-
-
-

-
-
-

-
-
-
-
-
-
-
-
-

1.
2.
3.
4.
5.

# VitePress SEO Guide

VitePress offers built-in SEO features like sitemap generation, meta tags, and fast static site generation for documentation and blogs.

[![Harlan Wilton](https://avatars.githubusercontent.com/u/5326365?v=4)Harlan Wilton](https://x.com/harlan-zw)7 mins read Published Dec 17, 2025

What you'll learn

- [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

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](#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](#seo-features)

### [Automatic Static HTML](#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](#built-in-sitemap-generation)

VitePress includes [native sitemap support](https://vitepress.dev/guide/sitemap-generation). Enable it in `.vitepress/config.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:

.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](#custom-sitemap-items)

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

.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](#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:

.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](#meta-tags-configuration)

### [Site-Level Meta Tags](#site-level-meta-tags)

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

.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](#page-level-meta-tags)

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

```
---
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](#dynamic-meta-tags)

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

.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](#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`:

.vitepress/config.ts

```
export default {
  themeConfig: {
    search: {
      provider: 'local'
    }
  }
}
```

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

### [Algolia DocSearch](#algolia-docsearch)

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

.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](#clean-urls)

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

.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](#vitepress-vs-nuxt-content)

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

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](#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?](#using-nuxt)

Nuxt offers deeper SEO integration through

, which handles sitemaps, robots.txt, structured data, and OG images with zero configuration.

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

---

On this page

- [When to Use VitePress](#when-to-use-vitepress)
- [SEO Features](#seo-features)
- [Meta Tags Configuration](#meta-tags-configuration)
- [Built-in Search](#built-in-search)
- [Clean URLs](#clean-urls)
- [VitePress vs Nuxt Content](#vitepress-vs-nuxt-content)
- [Limitations](#limitations)
- [Using Nuxt?](#using-nuxt)

[GitHub](https://github.com/harlan-zw/nuxt-seo) [ Discord](https://discord.com/invite/275MBUBvgP)

###

-
-

Modules

-
-
-
-
-
-
-
-
-

###

-
-
-

###

Nuxt

-
-
-
-
-

Vue

-
-
-
-
-
-
-
-

###

-
-
-
-
-
-
-
-
-
-

Copyright © 2023-2026 Harlan Wilton - [MIT License](https://github.com/harlan-zw/nuxt-seo/blob/main/license) · [mdream](https://mdream.dev)