---
title: "Prerendering"
description: "Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics"
canonical_url: "https://nuxt.com/docs/4.x/getting-started/prerendering"
---
# Prerendering

> Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics

Nuxt allows for select pages from your application to be rendered at build time. Nuxt will serve the prebuilt pages when requested instead of generating them on the fly.

<read-more to="https://nuxt.com/docs/4.x/guide/concepts/rendering" title="Nuxt rendering modes">



</read-more>

## Crawl-based Pre-rendering

Use the [`nuxt generate` command](https://nuxt.com/docs/4.x/api/commands/generate) to build and pre-render your application using the [Nitro](https://nuxt.com/docs/4.x/guide/concepts/server-engine) crawler. This command is similar to `nuxt build` with the `nitro.static` option set to `true`, or running `nuxt build --prerender`.

This will build your site, stand up a nuxt instance, and, by default, prerender the root page `/` along with any of your site's pages it links to, any of your site's pages they link to, and so on.

<code-group sync="pm">

```bash [npm]
npx nuxt generate
```

```bash [yarn]
yarn nuxt generate
```

```bash [pnpm]
pnpm nuxt generate
```

```bash [bun]
bun x nuxt generate
```

```bash [deno]
deno x nuxt generate
```

</code-group>

You can now deploy the `.output/public` directory to any static hosting service or preview it locally with `npx serve .output/public`.

Static and prerender builds also emit `200.html` and `404.html` SPA fallbacks. See [What are 200.html and 404.html?](https://nuxt.com/docs/4.x/guide/concepts/rendering#what-are-200html-and-404html).

How the Nitro crawler works:

1. Load the HTML of your application's root route (`/`), any non-dynamic pages in your `~/pages` directory, and any other routes in the `nitro.prerender.routes` array.
2. Save the HTML and `_payload.json` to the `~/.output/public/` directory to be served statically.
3. Find all anchor tags (`<a href="...">`) in the HTML to navigate to other routes.
4. Repeat steps 1-3 for each anchor tag found until there are no more anchor tags to crawl.

This is important to understand since pages that are not linked to a discoverable page can't be pre-rendered automatically.

<read-more to="https://nuxt.com/docs/4.x/api/commands/generate#nuxt-generate">

Read more about the `nuxt generate` command.

</read-more>

### Selective Pre-rendering

You can manually specify routes that [Nitro](https://nuxt.com/docs/4.x/guide/concepts/server-engine) will fetch and pre-render during the build or ignore routes that you don't want to pre-render like `/dynamic` in the `nuxt.config` file:

```ts [nuxt.config.ts]twoslash
// @errors: 2353
export default defineNuxtConfig({
  nitro: {
    prerender: {
      routes: ['/user/1', '/user/2'],
      ignore: ['/dynamic'],
    },
  },
})
```

You can combine this with the `crawlLinks` option to pre-render a set of routes that the crawler can't discover like your `/sitemap.xml` or `/robots.txt`:

```ts [nuxt.config.ts]twoslash
// @errors: 2353
export default defineNuxtConfig({
  nitro: {
    prerender: {
      crawlLinks: true,
      routes: ['/sitemap.xml', '/robots.txt'],
    },
  },
})
```

Setting `nitro.prerender` to `true` is similar to `nitro.prerender.crawlLinks` to `true`.

<read-more to="https://nitro.build/config#prerender">

Read more about pre-rendering in the Nitro documentation.

</read-more>

Lastly, you can manually configure this using routeRules.

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  routeRules: {
    // Set prerender to true to configure it to be prerendered
    '/rss.xml': { prerender: true },
    // Set it to false to configure it to be skipped for prerendering
    '/this-DOES-NOT-get-prerendered': { prerender: false },
    // Everything under /blog gets prerendered as long as it
    // is linked to from another page
    '/blog/**': { prerender: true },
  },
})
```

<read-more to="https://nitro.build/config#routerules">

Read more about Nitro's `routeRules` configuration.

</read-more>

As a shorthand, you can also configure this in a page file using [`defineRouteRules`](https://nuxt.com/docs/4.x/api/utils/define-route-rules).

<read-more to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#inlinerouterules" icon="i-lucide-star">

This feature is experimental and in order to use it you must enable the `experimental.inlineRouteRules` option in your `nuxt.config`.

</read-more>

```vue [app/pages/index.vue]
<script setup>
// Or set at the page level
defineRouteRules({
  prerender: true,
})
</script>

<template>
  <div>
    <h1>Homepage</h1>
    <p>Pre-rendered at build time</p>
  </div>
</template>
```

This will be translated to:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },
  },
})
```

## Payload Extraction

When Nuxt renders a page on the server, it serializes the results of your data fetching ([`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch)) and app state ([`useState`](https://nuxt.com/docs/4.x/api/composables/use-state)) into a payload so the client can hydrate without re-fetching. With payload extraction enabled, Nuxt also writes this payload to a `_payload.json` file alongside the route's HTML:

- Prerendered routes generate their payload file at build time.
- Routes using [ISR or SWR caching](https://nuxt.com/docs/4.x/guide/concepts/rendering#hybrid-rendering) generate their payload file when the route is first rendered, even on a hybrid (non-static) site.

During client-side navigation, Nuxt fetches the `_payload.json` file for the destination route and reuses the extracted data instead of running the data fetching again in the browser.

You can control this behavior with the [`experimental.payloadExtraction`](https://nuxt.com/docs/4.x/api/nuxt-config#payloadextraction) option:

- `'client'` - The payload is inlined in the HTML for the initial render and extracted to `_payload.json` files for client-side navigation. There is no extra network request on first load.
- `true` - The payload is extracted to a separate `_payload.json` file for both the initial render and client-side navigation. The HTML is smaller and the payload file can be cached by a CDN, at the cost of one extra request on first load.
- `false` - Payload extraction is disabled. The payload is always inlined in the HTML and no `_payload.json` files are generated.

The default is `true`, or `'client'` when `compatibilityVersion: 5` is set. It is forced to `false` when `ssr: false` is set.

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    payloadExtraction: 'client',
  },
})
```

A few practical consequences to be aware of:

- On a fully static site, client-side navigation reuses the data captured at build time, so data can be stale until the next rebuild.
- For ISR/SWR routes, CDNs can cache payload files alongside the HTML, improving client-side navigation performance for cached routes. Dynamic routes like `pages/[...slug].vue` can opt in with glob patterns such as `'/**': { isr: true }`.
- Payloads are serialized with [devalue](https://github.com/Rich-Harris/devalue), so custom types (such as class instances) need payload plugins with custom reducers and revivers to survive the round trip.

<read-more to="https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#payload" title="Payload reducers and revivers">



</read-more>

## Runtime Prerender Configuration

### `prerenderRoutes`

You can use this at runtime within a [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context) to add more routes for Nitro to prerender.

```vue [app/pages/index.vue]
<script setup>
prerenderRoutes(['/some/other/url'])
prerenderRoutes('/api/content/article/my-article')
</script>

<template>
  <div>
    <h1>This will register other routes for prerendering when prerendered</h1>
  </div>
</template>
```

<read-more to="https://nuxt.com/docs/4.x/api/utils/prerender-routes" title="prerenderRoutes">



</read-more>

### `prerender:routes` Nuxt hook

This is called before prerendering for additional routes to be registered.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  hooks: {
    async 'prerender:routes' (ctx) {
      const { pages } = await fetch('https://api.some-cms.com/pages').then(
        res => res.json(),
      )
      for (const page of pages) {
        ctx.routes.add(`/${page.name}`)
      }
    },
  },
})
```

### `prerender:generate` Nitro hook

This is called for each route during prerendering. You can use this for fine-grained handling of each route that gets prerendered.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  nitro: {
    hooks: {
      'prerender:generate' (route) {
        if (route.route?.includes('private')) {
          route.skip = true
        }
      },
    },
  },
})
```


## Sitemap

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