Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Rendering strategies: SSR, SPA and prerendering

So far every blog page has been rendered on the server on every request — that is SSR (server-side rendering). But not every site needs a running Node.js server. React Router supports two more strategies: SPA mode, where there is no server at all, and prerendering, where page HTML is generated once at build time. The strategy is chosen in react-router.config.ts.

The config file

It already exists in the project root:

// react-router.config.ts
import type { Config } from "@react-router/dev/config";
 
export default {
  ssr: true,
} satisfies Config;

ssr: true is the default: for every request the server calls the loader and renders HTML.

Prerendering

Pages that rarely change can be generated in advance. The prerender option takes a list of addresses:

// react-router.config.ts
import type { Config } from "@react-router/dev/config";
 
export default {
  ssr: true,
  prerender: ["/", "/about"],
} satisfies Config;

On npm run build the framework calls these pages' loaders and saves ready HTML files to build/client. Other pages are still rendered by the server. prerender: true generates all addresses without dynamic segments.

A list from data

For addresses with params prerender can be a function:

// react-router.config.ts
import type { Config } from "@react-router/dev/config";
 
export default {
  async prerender() {
    const ids = [1, 2, 3]; // for example, from the database
    return ["/", "/about", ...ids.map((id) => `/posts/${id}`)];
  },
} satisfies Config;

After the build, /posts/1, /posts/2 and /posts/3 exist as ready files.

SPA mode

// react-router.config.ts
import type { Config } from "@react-router/dev/config";
 
export default {
  ssr: false,
} satisfies Config;

With ssr: false the build produces a static site: build/client/index.html and JavaScript. You can put it on any static host. There are no server loader and action functions in this mode — data is loaded by clientLoader and clientAction in the browser. Prerendering can be combined with this mode too.

Comparison

StrategyNode.js serverData freshnessGood for
SSRRequiredEvery requestA blog with comments, user accounts
PrerenderingNot needed for those pagesAt build time"About us", documentation
SPANot neededFrom the browserInternal dashboards behind a login

Common mistake

Turning on ssr: false in a project that already has server loader functions with a database and sessions, and expecting everything to keep working. Without a server there is nowhere to run that code, and the build reports an error. Choose the rendering strategy early: a blog with comments and login needs SSR, and prerendering is added for individual static pages.

Thanks for reading!

Donate to the site — we work hard for you.