# Prerendering

Learn how to serve dynamic content on prerendered and statically generated pages.

If you prerender your Nuxt site for performance, you might worry that you can no longer run A/B tests, tailor content to each visitor, or update it from your CMS. You can. This guide explains why prerendering and dynamic content seem to be at odds, and shows the two ways to combine them so you can pick the right one for each page.

## Static vs. dynamic content

Prerendering compiles your pages into static HTML at build time. That is great for performance, but it also means the HTML is the same for everyone the moment it is generated.

Dynamic content, on the other hand, is decided at request time, whether that is an A/B test variant, content tailored to the visitor, or the latest content from your CMS. A fully prerendered page is frozen by the time the visitor sees it, so on its own it cannot adapt on the fly.

The good news is that you do not have to choose between the two for your whole site. Nuxt supports [hybrid rendering](https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering), which lets you set a different rendering rule per route, and the SDK ships both server-side and client-side composables. So you keep prerendering everywhere it makes sense and change the approach only for the pages that need dynamic content.

> **Good to know: What about fully static sites?**
>
> This guide assumes you use Nuxt's hybrid rendering, where each route can be prerendered or rendered on demand. If you fully export your site with `nuxi generate` instead, there is no server at runtime. The SDK can run entirely on the client side, so your content still works, as shown in [Render on the client](#client).

## Choosing an approach

There are two ways to serve dynamic content on a page without giving up prerendering across the rest of your site.

|                             | Server-side rendering | Client-side rendering |
| --------------------------- | --------------------- | --------------------- |
| Final content on first load | ✓                     | ✗                     |
| No content flicker          | ✓                     | ✗                     |
| Visible to crawlers         | ✓                     | ✗                     |
| Served as a static file     | ✗                     | ✓                     |
| Runs without a server       | ✗                     | ✓                     |

For most cases we recommend rendering these pages on the server. The experience is smoother, there is no content flicker, and the content is visible to search engines. Reach for client-side rendering when a page must remain a fully static file, for example when it is served from a CDN with no server at all.

## Render on the server \[#server]

For the pages that need dynamic content, opt out of prerendering with a [route rule](https://nuxt.com/docs/api/nuxt-config#routerules). They will be rendered on the server per request, so the right content is decided server-side and is already in the first HTML response.

**nuxt.config.ts**

```ts
export default defineNuxtConfig({
  routeRules: {
    // Render these pages on the server.
    '/': {prerender: false},
    '/pricing': {prerender: false},

    // Prerender everything else for maximum performance.
    '/**': {prerender: true},
  },
});
```

On those pages, use the content as usual. The default [`useContent`](api/composables/use-content) composable and [`<Slot>`](api/components/slot-content) component resolve the content on the server, with no extra setup:

**pages/index.vue**

```vue
<script setup>
const {data} = await useContent('home-hero');
</script>

<template>
  <div v-if="data">
    <strong>{{ data.content.title }}</strong>
    <p>{{ data.content.subtitle }}</p>
  </div>
</template>
```

The rest of your site stays prerendered, so only the pages that need it are rendered on the server. If you want to cache those responses, you can combine the route rule with [caching options](https://nuxt.com/docs/api/nuxt-config#routerules) like `swr` or `isr`.

## Render on the client \[#client]

When a page must stay prerendered, keep it in the prerendered set and load the content in the browser. The page ships static, and the content updates right after it appears.

> **Good to know: When is client-side rendering a good fit?**
>
> Client-side rendering works well whenever a brief loading state is acceptable. Below-the-fold sections are a common example, such as a recommendations block, a "related articles" list, or a promo banner further down the page, where a skeleton placeholder while the content loads does not hurt the experience.

**nuxt.config.ts**

```ts
export default defineNuxtConfig({
  routeRules: {
    // Keep the page static; the content loads in the browser.
    '/': {prerender: true},
  },
});
```

These composables fetch in the browser and always need an [`initial`](/reference/sdk/vue/api/composables/use-content#options-initial-prop) value, which is rendered into the static HTML and shown to visitors and crawlers until the content loads. Without it, the build fails with a [missing slot content](/reference/sdk/vue/troubleshooting/problem/missing-slot-content) error.

**pages/index.vue**

```vue
<script setup>
import {useContent} from '@croct/plug-nuxt/csr';

const {data} = useContent('home-hero', {
  initial: {
    title: 'Welcome to Croct!',
    subtitle: 'The easiest way to personalize your application.',
  },
});
</script>

<template>
  <div v-if="data">
    <strong>{{ data.title }}</strong>
    <p>{{ data.subtitle }}</p>
  </div>
</template>
```

> **Avoid build-time fetching**
>
> Use `useContent` and `<Slot>` from `@croct/plug-nuxt/csr`, not the default ones, which run at build time and would freeze the content for every visitor.

## Explore

- [Content rendering](content-rendering): Learn how to fetch and render content for your slots.
- [Hybrid rendering](https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering): See how Nuxt applies different rendering rules per route.
