Server-side Rendering (SSR)

Server-side rendering allows you to pre-render an initial page visit on the server, and to send the rendered HTML to the browser. This allows visitors to see and interact with your pages before they have fully loaded, and also provides other benefits such as decreasing the time it takes for search engines to index your site.

SSR is not yet ready for the Svelte adapter. However, it's something we're actively working on adding.

How it works

When Inertia detects that it's running in a Node.js environment, it will automatically render the provided page object to HTML and return it.

However, because most Inertia applications are built in languages such as PHP or Ruby, we'll need to hand the request over to a separate Node.js service so that it can render the page for us, and return the rendered HTML back to the browser when it's done.

Setting up server side rendering

First, we'll install the necessary server-side rendering dependencies using NPM or Yarn:

npm install @vue/server-renderer
yarn add @vue/server-renderer

We'll also install the @inertiajs/server package, which provides a simple HTTP server. While this package isn't strictly necessary, it prevents the need to write your own HTTP service, and generally keeps things simple:

npm install @inertiajs/server
yarn add @inertiajs/server

Then, we'll create a resources/js/ssr.js file:

touch resources/js/ssr.js

This file is going to look very similar like your app.js file, with the exception that it's not going to run in the browser, but rather in Node.js. Here's a complete example:

import { createSSRApp, h } from 'vue'
import { renderToString } from '@vue/server-renderer'
import { createInertiaApp } from '@inertiajs/inertia-vue3'
import createServer from '@inertiajs/server'

createServer((page) => createInertiaApp({
  page,
  render: renderToString,
  resolve: name => require(`./Pages/${name}`),
  setup({ app, props, plugin }) {
    return createSSRApp({
      render: () => h(app, props),
    }).use(plugin)
  },
}))
Be sure to add anything that's missing from your app.js file that makes sense to run in SSR mode, such as plugins or custom mixins. However, not everything needs to be included. For example, the InertiaProgress library can be omitted from this file, as it will never be used in SSR mode.

Furthermore, do not use code-splitting in your ssr.js file as it won't help anything, given that we want to generate just one SSR build file. You can, of course, still use code splitting for your client-side build (app.js).
By default, Inertia's SSR server will operate on port 13714. However, you can change this by providing a second argument to the createServer method.
Vue 2: If you're using the PortalVue package, it's import line MUST come after the import { createRenderer } from 'vue-server-renderer' line.

Setting up Laravel Mix

In order for our Webpack build to run properly on Node, we'll first need to install the webpack-node-externals package:

npm install webpack-node-externals

Then, we'll create a new webpack.ssr.mix.js file for SSR. This is necessary, because at the time of writing this, Laravel Mix does not support multiple webpack configurations within the same webpack.mix.js file:

touch webpack.ssr.mix.js

Here is an example configuration for this file. Note that it will look much like your webpack.mix.js configuration, with the exception that you only compile your JavaScript, and not your CSS.

Be sure to redefine any aliases used within your application. Using webpackConfig(), be sure to set the target to node, and set externals to [webpackNodeExternals()], which is the library we just installed.

const path = require('path')
const mix = require('laravel-mix')
const webpackNodeExternals = require('webpack-node-externals')

mix
  .options({ manifest: false })
  .js('resources/js/ssr.js', 'public/js')
  .vue({ version: 3, options: { optimizeSSR: true } })
  .alias({ '@': path.resolve('resources/js') })
  .webpackConfig({
    target: 'node',
    externals: [webpackNodeExternals()],
  })

Enabling server side rendering

Automatic SSR rendering is currently only available for the Laravel adapter. However, we're actively working on adding this to the Rails adapter as well.

Next, we'll need to make sure the @inertiaHead directive is included in the <head> section of our app.blade.php file:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    <link href="{{ mix('/css/app.css') }}" rel="stylesheet">
    <script src="{{ mix('/js/app.js') }}" defer></script>
    @inertiaHead
  </head>
  <body>
    @inertia
  </body>
</html>

Finally, we'll need to enable SSR in your application's inertia.php configuration file. If you do not yet have this file in your application's config folder, you should publish it first using the following command:

php artisan vendor:publish --provider="Inertia\ServiceProvider"

Then, enable SSR by setting the enabled option under ssr to true:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Server Side Rendering
    |--------------------------------------------------------------------------
    |
    | These options configures if and how Inertia uses Server Side Rendering
    | to pre-render the initial visits made to your application's pages.
    |
    | Do note that enabling these options will NOT automatically make SSR work,
    | as a separate rendering service needs to be available. To learn more,
    | please visit https://inertiajs.com/server-side-rendering
    |
    */

    'ssr' => [

        'enabled' => true,

        'url' => 'http://127.0.0.1:13714/render',

    ],

// ...

Building your application

You now have two build processes you need to run—one for your client-side bundle, and another for your server-side bundle:

npx mix
npx mix --mix-config=webpack.ssr.mix.js

Run both of these build steps and correct any errors that are generated. Remember, you're now building an "isomorphic" app, which means your app runs both on the client (browser) and on the server (Node).

To learn more about SSR in Vue 2, see their guide. To learn more about SSR in Vue 3, see their guide. To learn more about SSR in React, see their guide.

Running the Node.js service

With the builds generated, you should be able run the Node server using the following command:

node public/js/ssr.js

With that running, you should now be able to access your app within the browser, with server-side rendering enabled. In fact, you should be able to disable JavaScript entirely and navigate around the app.

Client side hydration (Vue-only)

With this configuration, Vue will automatically try to "hydrate" the static markup and make it interactive, instead of re-rendering all the HTML that we just generated on the server. This is called "client side hydration". However, for client side hydration to work, the HTML generated on the server must be exactly the same as on the client, otherwise you'll see this warning in your console:

Of course, since you're generating the HTML from the same page components, this generally isn't an issue. However, if you do see this warning, see these caveats in the Vue 2 / Vue 3 SSR documentation.

[Vue warn]: Hydration children mismatch...

Hosting setup

When deploying your SSR enabled app to production, you'll need to run both the client-side (app.js) and server-side (ssr.js) builds. One option here is to update the prod script in package.json to run both builds automatically:

"prod": "mix --production && mix --production --mix-config=webpack.ssr.mix.js",

Laravel Forge

To run the SSR server on Forge, create a new daemon that runs node public/js/ssr.js in the root of your app.

Take note of the daemon ID that is generated, as you'll need to use this in your apps deployment script. Whenever you deploy your application, you'll need to automatically restart the SSR server. Add the following to your deployment script, updating "123456" with your daemon ID.

# Restart SSR server
sudo supervisorctl restart daemon-123456:daemon-123456_00

Heroku

To run the SSR server on Heroku, update your web configuration in your Procfile to first run the SSR server before starting your web server. Note, to do this you must have the heroku/nodejs buildpack installed in addition to the heroku/php buildback.

web: node public/js/ssr.js & vendor/bin/heroku-php-apache2 public/