Configuring Server-Side Rendering In A Laravel + Vue + Inertia Project

Update. Code snippets updated to use Inertia.js 1.0.

My last article provided a detailed step-by-step guide about adding Vue.js and Inertia.js to a Laravel project.

All is good, but here is one little problem. It renders pages using JavaScript, and it may be bad for SEO. This article aims to fix this.

The solution is to render pages on the server and here is how to configure it:

  1. Create a resources/js/ssr.js file, which is going to be similar to app.js file, with the exception that it's not going to run in the browser, but rather in Node.js:

     import '../css/app.css';
     import { createSSRApp, h } from 'vue'
     import { renderToString } from 'vue/server-renderer'
     import { createInertiaApp } from '@inertiajs/inertia-vue3'
     import createServer from '@inertiajs/vue3/server'
     createServer((page) => createInertiaApp({
         render: renderToString,
         resolve: name => {
             const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
             return pages[`./Pages/${name}.vue`]
         setup: ({ app, props, plugin }) => {
             return createSSRApp({
                 render: () => h(app, props)
  2. Add SSR configuration to vite.config.js:

     export default defineConfig({
         plugins: [
                 ssr: 'resources/js/ssr.js',
         ssr: {
             // fix, see
             noExternal: ['@inertiajs/server'],
  3. Add instructions to build SSR version of your app to the package.json:

         "scripts": {
             "build": "vite build && vite build --ssr"
  4. Create config/inertia.php file by running the following command:

     php artisan vendor:publish --provider="Inertia\ServiceProvider"
  5. Enable SSR in the config/inertia.php:

     return [
         'ssr' => [
             'enabled' => true,
  6. Instead of npm run dev, run the following:

     npm run build
     node bootstrap/ssr/ssr.mjs
  7. Refresh the page and check the page source to see that the main application <div> is no longer empty.