Prerendering
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{title="Nuxt rendering modes" to="/docs/4.x/guide/concepts/rendering"}
Crawl-based Pre-rendering#
Use the nuxt generate command to build and pre-render your application using the Nitro 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
::
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?](/docs/4.x/guide/concepts/rendering#what-are-200html-and-404html).
Working of the Nitro crawler:
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="/docs/4.x/api/commands/generate#nuxt-generate"}
Read more about the `nuxt generate` command.
::
### Selective Pre-rendering
You can manually specify routes that [Nitro](/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 twoslash [nuxt.config.ts]
// @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 twoslash [nuxt.config.ts] // @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.
::
Lastly, you can manually configure this using routeRules.
```ts twoslash [nuxt.config.ts]
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.
::
As a shorthand, you can also configure this in a page file using defineRouteRules.
::read-more{to="/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.
::
```vue [app/pages/index.vue]
Pre-rendered at build time
Homepage
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 and useFetch) and app state (useState) 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 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 option:
'client'- The payload is inlined in the HTML for the initial render and extracted to_payload.jsonfiles for client-side navigation. There is no extra network request on first load.true- The payload is extracted to a separate_payload.jsonfile 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.jsonfiles are generated.
The default is true, or 'client' when compatibilityVersion: 5 is set. It is forced to false when ssr: false is set.
```ts twoslash [nuxt.config.ts] 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{title="Payload reducers and revivers" to="/docs/4.x/api/composables/use-nuxt-app#payload"}
## Runtime Prerender Configuration
### `prerenderRoutes`
You can use this at runtime within a [Nuxt context](/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{title="prerenderRoutes" to="/docs/4.x/api/utils/prerender-routes"}
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
}
},
},
},
})