---
title: Pre-Rendering
---
# Pre-Rendering
Pre-Rendering allows you to speed up page loads for static content by rendering pages at build time instead of at runtime. Pre-rendering is enabled via the `prerender` config in `react-router.config.ts` and can be used in two ways based on the `ssr` config value:
- Alongside a runtime SSR server with `ssr:true` (the default value)
- Deployed to a static file server with `ssr:false`
## Pre-rendering with `ssr:true`
### Configuration
Add the `prerender` option to your config, there are three signatures:
```ts filename=react-router.config.ts lines=[7-8,10-11,13-21]
import type { Config } from "@react-router/dev/config";
export default {
// Can be omitted - defaults to true
ssr: true,
// all static paths (no dynamic segments like "/post/:slug")
prerender: true,
// specific paths
prerender: ["/", "/blog", "/blog/popular-post"],
// async function for dependencies like a CMS
async prerender({ getStaticPaths }) {
let posts = await fakeGetPostsFromCMS();
return [
"/",
"/blog",
...posts.map((post) => post.href),
];
},
} satisfies Config;
```
### Data Loading and Pre-rendering
There is no extra application API for pre-rendering. Routes being pre-rendered use the same route `loader` functions as server rendering:
```tsx
export async function loader({ request, params }) {
let post = await getPost(params.slug);
return post;
}
export function Post({ loaderData }) {
return
{loaderData.title}
;
}
```
Instead of a request coming to your route on a deployed server, the build creates a `new Request()` and runs it through your app just like a server would.
When server rendering, requests to paths that have not been pre-rendered will be server rendered as usual.
### Static File Output
The rendered result will be written out to your `build/client` directory. You'll notice two files for each path:
- `[url].html` HTML file for initial document requests
- `[url].data` file for client side navigation browser requests
The output of your build will indicate what files were pre-rendered:
```sh
> react-router build
vite v5.2.11 building for production...
...
vite v5.2.11 building SSR bundle for production...
...
Prerender: Generated build/client/index.html
Prerender: Generated build/client/blog.data
Prerender: Generated build/client/blog/index.html
Prerender: Generated build/client/blog/my-first-post.data
Prerender: Generated build/client/blog/my-first-post/index.html
...
```
During development, pre-rendering doesn't save the rendered results to the public directory, this only happens for `react-router build`.
## Pre-rendering with `ssr:false`
The above examples assume you are deploying a runtime server but are pre-rendering some static pages to avoid hitting the server, resulting in faster loads.
To disable runtime SSR and configure pre-rendering to be served from a static file server, you can set the `ssr:false` config flag:
```ts filename=react-router.config.ts
import type { Config } from "@react-router/dev/config";
export default {
ssr: false, // disable runtime server rendering
prerender: true, // pre-render all static routes
} satisfies Config;
```
If you specify `ssr:false` without a `prerender` config, React Router refers to that as [SPA Mode](./spa). In SPA Mode, we render a single HTML file that is capable of hydrating for _any_ of your application paths. It can do this because it only renders the `root` route into the HTML file and then determines which child routes to load based on the browser URL during hydration. This means you can use a `loader` on the root route, but not on any other routes because we don't know which routes to load until hydration in the browser.
If you want to pre-render paths with `ssr:false`, those matched routes _can_ have loaders because we'll pre-render all of the matched routes for those paths, not just the root. You cannot include `actions` or `headers` functions in any routes when `ssr:false` is set because there will be no runtime server to run them on.
### Pre-rendering with a SPA Fallback
If you want `ssr:false` but don't want to pre-render _all_ of your routes - that's fine too! You may have some paths where you need the performance/SEO benefits of pre-rendering, but other pages where a SPA would be fine.
You can do this using the combination of config options as well - just limit your `prerender` config to the paths that you want to pre-render and React Router will also output a "SPA Fallback" HTML file that can be served to hydrate any other paths (using the same approach as [SPA Mode](./spa)).
This will be written to one of the following paths:
- `build/client/index.html` - If the `/` path is not pre-rendered
- `build/client/__spa-fallback.html` - If the `/` path is pre-rendered
```ts filename=react-router.config.ts
import type { Config } from "@react-router/dev/config";
export default {
ssr: false,
// SPA fallback will be written to build/client/index.html
prerender: ["/about-us"],
// SPA fallback will be written to build/client/__spa-fallback.html
prerender: ["/", "/about-us"],
} satisfies Config;
```
You can configure your deployment server to serve this file for any path that otherwise would 404. Some hosts do this by default, but others don't. As an example, a host may support a `_redirects` file to do this:
```
# If you did not pre-render the `/` route
/* /index.html 200
# If you pre-rendered the `/` route
/* /__spa-fallback.html 200
```
If you're getting 404s at valid routes for your app, it's likely you need to configure your host.
Here's another example of how you can do this with the [`sirv-cli`](https://www.npmjs.com/package/sirv-cli#user-content-single-page-applications) tool:
```sh
# If you did not pre-render the `/` route
sirv-cli build/client --single index.html
# If you pre-rendered the `/` route
sirv-cli build/client --single __spa-fallback.html
```
### Invalid Exports
When pre-rendering with `ssr:false`, React Router will error at build time if you have invalid exports to help prevent some mistakes that can be easily overlooked.
- `headers`/`action` functions are prohibited in all routes because there will be no runtime server on which to run them
- When using `ssr:false` without a `prerender` config (SPA Mode), a `loader` is permitted on the root route only
- When using `ssr:false` with a `prerender` config, a `loader` is permitted on any route matched by a `prerender` path
- If you are using a `loader` on a pre-rendered route that has child routes, you will need to make sure the parent `loaderData` can be determined at run-time properly by either:
- Pre-rendering all child routes so that the parent `loader` can be called at build-time for each child route path and rendered into a `.data` file, or
- Use a `clientLoader` on the parent that can be called at run-time for non-pre-rendered child paths