Server-side rendering (SSR)

This feature is currently in early access, and is only available to our sponsors. To gain access to this feature now, please support this project financially by becoming a sponsor. 🧡

While Inertia apps are client-side rendered (using Vue, React, or Svelte), it's also possible to have them first rendered server-side on the first page load. This can improve search engine optimization (SEO) and also reduce the time to first contentful paint (FCP).

How it works

The challenge with server-side rendering JavaScript frameworks like Vue, React and Svelte is that they were designed to render in the browser, not on a server. Fortunately, thanks to Node.js, it's possible to also render these frameworks server-side!

Vue, React and Svelte all offer SSR tooling, which Inertia can take advantage of. Here's how it works:

  1. A request comes into your server-side framework
    Your requests and responses are still fully managed by your server-side framework of choice. Your routes, middleware, and controllers prepare the Inertia response, just like a normal Inertia app.
  2. Inertia makes a request to a local Node SSR server
    Right before your app sends the full page response to the browser, Inertia takes the page object for that response and sends it via HTTP to a local Node SSR server.
  3. The Node SSR server renders the page component as HTML
    Using the page object that was provided, the Node server knows what Vue/React/Svelte page component to render, and which props to pass it. It then returns the rendered HTML back to your app.
  4. Your app inserts the pre-rendered HTML in the response
    Now that your app has the pre-rendered HTML for the page, it can include it in the HTML response sent to the browser. When the client-side framework boots, it is able to "hydrate" the server-side rendered HTML, instead of re-rendering the whole page.

What's awesome here is that, because of Inertia's architecture, the page object sent to the Node SSR server always includes all the necessary data (props) needed for the page component to render.

Meaning, you don't run into any asynchronous data loading issues when doing server-side rendering with Inertia. It's very fast. Our tests show that it takes between 2ms-50ms to render a page, depending on its complexity.

Also, keep in mind that Inertia only needs to do server-side rendering for the first page load. From that point on, you're in "SPA mode", and you just get normal Inertia XHR responses back.

Inertia SSR does not pre-render your pages at build time, but rather server-side renders them on demand, just like a classic server-side rendered application. Which means it works for pages that contain dynamic content, like the currently authenticated user, or data from a database.

Requirements

Okay, what are the gotchas? There are a few technical requirements to be aware of.

First, since we're using Node to do the server-side rendering, you'll need Node installed on your server. Fortunately, since Node is often used for build steps, it's very common for it to be installed.

Second, you need to run a small background Node process. If you're using a modern hosting platform like Heroku or Laravel Forge, it's quite straightforward to setup. (Technically you could avoid running the background Node process, and just shell out to Node directly. However, since Node takes about 250ms to boot up, this approach comes at a pretty significant performance penalty.)

Third, you are now building an app that must be able to run in both the browser and in Node. These are sometimes called "universal" or "isomorphic" apps. Generally speaking this is quite manageable. You just need to be aware of this when reaching for window or document, as these don't exist in Node.

Demo app

Wondering what a server-side rendered Inertia app feels like? We've setup the Ping CRM demo app in "SSR mode" so you can find out.

You can find it at ssr-demo.inertiajs.com.

Be sure to view the source to see the HTML coming back from the server. Or, even better, login, disable JavaScript, and then click around the app. The pages load, even though JavaScript is disabled! 🤩

This demo app is running on a small Digital Ocean droplet, managed by Laravel Forge.