---
title: "How to Generate a Sitemap in Vue 3"
description: "Generate an XML sitemap for a Vue app with a Vite plugin or static file. Use accurate modification dates and submit the result to Search Console."
canonical_url: "https://nuxtseo.com/learn-seo/vue/controlling-crawlers/sitemaps"
last_updated: "2026-10-08"
---

> Index of every page on this site: [llms.txt](https://nuxtseo.com/llms.txt)

::key-takeaways
- Sitemaps are limited to 50,000 URLs or 50MB; use a sitemap index for larger sites
- Only include indexable pages, skipping noindexed, redirected, or error pages
- Submit to Google Search Console and reference the sitemap in robots.txt
::

The `sitemap.xml` file helps search engines discover your pages. Google considers sites "small" if they have [500 pages or fewer](https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview). You likely need a sitemap if you exceed this, have a new site with few backlinks, or update content frequently. Pair it with a solid [internal linking structure](https://nuxtseo.com/learn-seo/vue/routes-and-rendering/internal-linking) and a [pre-launch warmup](https://nuxtseo.com/learn-seo/pre-launch-warmup) strategy to speed up discovery.

## Static Sitemap

If your URL list is small enough to maintain manually, create a static sitemap in your public directory:

```dir
public/
  sitemap.xml
```

Add your URLs with proper formatting:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://mysite.com/</loc>
    <lastmod>2026-01-03</lastmod>
  </url>
  <url>
    <loc>https://mysite.com/about</loc>
    <lastmod>2026-01-15</lastmod>
  </url>
</urlset>
```

Sitemaps are limited to [50,000 URLs or 50MB uncompressed](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap). Use UTF-8 encoding and absolute URLs only.

## Build-Time Generation with Vite

Install with `pnpm add -D vite-plugin-sitemap`. Add [vite-plugin-sitemap](https://github.com/jbaubree/vite-plugin-sitemap) to your existing [Vite](https://vite.dev) plugins to generate sitemaps during build:

```ts [vite.config.ts]
import { defineConfig } from 'vite'
import Sitemap from 'vite-plugin-sitemap'

export default defineConfig({
  plugins: [
    Sitemap({
      hostname: 'https://mysite.com',
      dynamicRoutes: [
        '/blog/post-1',
        '/blog/post-2'
      ],
      // Illustrative content dates. Replace with actual modification dates.
      lastmod: {
        '/': new Date('2026-09-01'),
        '/blog/post-1': new Date('2026-09-02'),
        '/blog/post-2': new Date('2026-09-03')
      }
    })
  ]
})
```

After running `pnpm exec vite build`{lang="bash"}, this generates `sitemap.xml`{lang="bash"} and `robots.txt`{lang="bash"} in your dist folder.

If you're using Vue Router, generate concrete page paths from your content data. Expand route parameters such as :slug into published URLs before generating the sitemap.

The plugin defaults modification dates to the build time. Supply accurate dates for every generated URL, including routes discovered from HTML files.

Avoid hash-based routing (`/#/about`{lang="bash"}): search engines ignore everything after the `#`, so hash-routed pages collapse into a single URL and can't be listed individually in a sitemap. Use history mode instead.

## Server-Side Sitemap Generation

For frequently changing content, generate the sitemap from your published page records. Use an XML serializer instead of inserting raw URLs into template strings. Query strings can contain characters that need XML escaping. Return application/xml and include absolute canonical URLs.

Keep your page loader and serialization at the server boundary. For a Vue SPA, a build script can generate the same static file. SSR is not required to serve a sitemap.

## XML Sitemap Tags

A basic sitemap uses these elements:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://mysite.com/page</loc>
    <lastmod>2026-01-03</lastmod>
  </url>
</urlset>
```

| Tag                         | Status      | Google Uses?                                                                                                        |
| --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------- |
| `<loc>`{lang="html"}        | Required    | Yes, the page URL                                                                                                   |
| `<lastmod>`{lang="html"}    | Recommended | Yes, [if consistently accurate](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap) |
| `<changefreq>`{lang="html"} | Skip        | [No, Google ignores this](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap)       |
| `<priority>`{lang="html"}   | Skip        | [No, Google ignores this](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap)       |

Google only uses `<lastmod>`{lang="html"} [if it's consistently and verifiably accurate](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap), meaning it can compare the date against the page's actual last modification. Update it when main content, structured data, or links change, not on every deploy.

Google ignores `<changefreq>`{lang="html"} and `<priority>`{lang="html"}, so omit them if Google is your target.

## Sitemap Index for Large Sites

If you exceed 50,000 URLs or 50MB, [split your sitemap into multiple files](https://developers.google.com/search/docs/crawling-indexing/sitemaps/large-sitemaps):

```xml [sitemap-index.xml]
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://mysite.com/sitemap-products.xml</loc>
    <lastmod>2026-01-03</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://mysite.com/sitemap-blog.xml</loc>
    <lastmod>2026-01-10</lastmod>
  </sitemap>
</sitemapindex>
```

Submit the index file to Google Search Console. Submission helps discovery but does not guarantee a fetch, crawl, or indexing.

## Push-Based Discovery with IndexNow

Sitemaps are pull-based: crawlers check them on their own schedule. [IndexNow](https://www.indexnow.org/faq) lets you notify participating engines when a URL changes. Submission does not guarantee crawling or indexing. See the [IndexNow guide](https://nuxtseo.com/learn-seo/vue/launch-and-listen/indexnow) for key-file setup and response checks.

## Specialized Sitemaps

### News Sitemap

News publishers should create [separate news sitemaps](https://developers.google.com/search/docs/crawling-indexing/sitemaps/news-sitemap) with articles from the last 2 days:

```xml [sitemap-news.xml]
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
  <url>
    <loc>https://mysite.com/article</loc>
    <news:news>
      <news:publication>
        <news:name>Site Name</news:name>
        <news:language>en</news:language>
      </news:publication>
      <news:publication_date>2026-01-29T12:00:00+00:00</news:publication_date>
      <news:title>Article Title</news:title>
    </news:news>
  </url>
</urlset>
```

Remove articles older than 2 days to keep the sitemap fresh; don't create new sitemaps daily, update the existing one.

### Image Sitemap

For galleries or image-heavy sites, add image metadata:

```xml [sitemap.xml]
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
  <url>
    <loc>https://mysite.com/page</loc>
    <image:image>
      <image:loc>https://mysite.com/image.jpg</image:loc>
    </image:image>
  </url>
</urlset>
```

[Image sitemaps help Google find images loaded via JavaScript](https://developers.google.com/search/docs/crawling-indexing/sitemaps/image-sitemaps) or not directly linked in HTML.

## Submit to Google Search Console

After generating your sitemap, [submit it to Google Search Console](https://support.google.com/webmasters/answer/7451001):

1. [Verify site ownership](https://nuxtseo.com/learn-seo/vue/launch-and-listen/search-console) (DNS, HTML file upload, or Google Analytics)
2. Navigate to **Sitemaps** under **Indexing**
3. Enter your sitemap URL: `https://mysite.com/sitemap.xml`{lang="bash"}
4. Click **Submit**

Google processes the sitemap and reports status:

- **Success**: sitemap accepted, pages discovered
- **Pending**: processing in progress
- **Couldn't fetch**: URL wrong or blocked by robots.txt

Check the Sitemaps report for fetch status and discovered URLs. Use the Page Indexing report to investigate indexing reasons.

In [October 2026 conference reporting](https://www.seroundtable.com/google-crawling-indexing-serving-data-42225.html), typical sitemap processing took about 24 hours. Slow cases took up to 14 days or never completed because of quality.

Processing the file does not mean its URLs are indexed. See [Google Search timelines](https://nuxtseo.com/learn-seo/google-search-timelines) before treating a wait as a failure.

### Before Submitting

Validate your sitemap:

- XML syntax is valid (use an [online validator](https://www.xml-sitemaps.com/validate-xml-sitemap.html))
- All URLs return 200 status (not 404 or 500)
- URLs match [canonical URLs](https://nuxtseo.com/learn-seo/vue/controlling-crawlers/canonical-urls) exactly
- `<lastmod>`{lang="html"} dates are accurate
- File uses UTF-8 encoding

### Alternative Submission

Reference your sitemap in `robots.txt`{lang="bash"}:

```txt [public/robots.txt]
User-agent: *
Allow: /

Sitemap: https://mysite.com/sitemap.xml
```

Google discovers this automatically when [crawling your robots.txt](https://nuxtseo.com/learn-seo/vue/controlling-crawlers/robots-txt).

### Troubleshooting "Couldn't Fetch"

Search Console sometimes shows **"Couldn't fetch"** or **"Sitemap could not be read"** even though the sitemap validates and loads fine in a browser. [Google lists several causes](https://support.google.com/webmasters/answer/7451001) for this status: the sitemap is blocked by `robots.txt`, the URL is wrong (a 404), the site has an unresolved manual action, or the fetch simply failed.

1. **Rule out the obvious first.** Confirm the sitemap URL loads directly, isn't blocked in `robots.txt`, and your site has no pending manual action.
2. **Use the URL Inspection tool** in Search Console. Paste your sitemap URL and click **Live test**. A successful fetch confirms current access. It does not prove XML validity or that an earlier error was transient.
3. **Give it time.** Google says some fetch errors are transient and resolve on later crawl attempts, so wait and check back rather than resubmitting immediately.

If it's still failing after checking the above, inspect the reported error and last read time. A resubmission is a request, not a forced fetch. Keep a stable sitemap URL while diagnosing the cause.

Using Nuxt? [Nuxt SEO](https://nuxtseo.com/docs/nuxt-seo/getting-started/introduction) provides sitemap generation and robots.txt configuration. Google decides which pages to index. [Learn more about sitemaps in Nuxt →](https://nuxtseo.com/learn-seo/nuxt/controlling-crawlers/sitemaps)

## Checklist

::checklist{#vue-sitemaps}
- Sitemap includes every indexable URL, none blocked by `robots.txt` or `noindex`
- URLs use history mode, no `#` hash routing
- `<lastmod>`{lang="html"} dates are accurate, not blanket-set on every build
- Sitemap stays under 50,000 URLs and 50MB, split into an index if not
- Sitemap submitted in Google Search Console and referenced in `robots.txt`
::

## Sitemap

See the full [sitemap](https://nuxtseo.com/sitemap.md) for all pages.
