> ## Documentation Index
> Fetch the complete documentation index at: https://inertiajs.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Server-Side Rendering (SSR)

export const Vue3Specific = ({children}) => {
  const [code, setCode] = useState(() => {
    if (typeof window === "undefined") {
      return null;
    }
    return localStorage.getItem("code")?.replace(/"/g, "") || null;
  });
  useEffect(() => {
    const handler = event => {
      if (event.detail?.key === "code") {
        setCode(event.detail.value?.replace(/"/g, ""));
      }
    };
    window.addEventListener("localStorageUpdate", handler);
    return () => window.removeEventListener("localStorageUpdate", handler);
  }, []);
  if (code !== "Vue 3") {
    return null;
  }
  return children;
};

export const Vue2Specific = ({children}) => {
  const [code, setCode] = useState(() => {
    if (typeof window === "undefined") {
      return null;
    }
    return localStorage.getItem("code")?.replace(/"/g, "") || null;
  });
  useEffect(() => {
    const handler = event => {
      if (event.detail?.key === "code") {
        setCode(event.detail.value?.replace(/"/g, ""));
      }
    };
    window.addEventListener("localStorageUpdate", handler);
    return () => window.removeEventListener("localStorageUpdate", handler);
  }, []);
  if (code !== "Vue 2") {
    return null;
  }
  return children;
};

export const VueSpecific = ({children}) => {
  const [code, setCode] = useState(() => {
    if (typeof window === "undefined") {
      return "Vue";
    }
    return localStorage.getItem("code")?.replace(/"/g, "") || "Vue";
  });
  useEffect(() => {
    const handler = event => {
      if (event.detail?.key === "code") {
        setCode(event.detail.value?.replace(/"/g, ""));
      }
    };
    window.addEventListener("localStorageUpdate", handler);
    return () => window.removeEventListener("localStorageUpdate", handler);
  }, []);
  if (code !== "Vue") {
    return null;
  }
  return children;
};

export const SvelteSpecific = ({children}) => {
  const [code, setCode] = useState(() => {
    if (typeof window === "undefined") {
      return null;
    }
    return localStorage.getItem("code")?.replace(/"/g, "") || null;
  });
  useEffect(() => {
    const handler = event => {
      if (event.detail?.key === "code") {
        setCode(event.detail.value?.replace(/"/g, ""));
      }
    };
    window.addEventListener("localStorageUpdate", handler);
    return () => window.removeEventListener("localStorageUpdate", handler);
  }, []);
  if (!code?.includes("Svelte")) {
    return null;
  }
  return children;
};

export const ReactSpecific = ({children}) => {
  const [code, setCode] = useState(() => {
    if (typeof window === "undefined") {
      return null;
    }
    return localStorage.getItem("code")?.replace(/"/g, "") || null;
  });
  useEffect(() => {
    const handler = event => {
      if (event.detail?.key === "code") {
        setCode(event.detail.value?.replace(/"/g, ""));
      }
    };
    window.addEventListener("localStorageUpdate", handler);
    return () => window.removeEventListener("localStorageUpdate", handler);
  }, []);
  if (code !== "React") {
    return null;
  }
  return children;
};

export const ClientSpecific = ({children}) => {
  const [nada, setNada] = useState();
  return children;
};

<Warning>This is documentation for Inertia.js v1, which is no longer actively maintained. Please refer to the [v3 docs](/v3/getting-started/index).</Warning>

Server-side rendering pre-renders your JavaScript pages on the server, allowing your visitors to receive fully rendered HTML when they visit your application. Since fully rendered HTML is served by your application, it's also easier for search engines to index your site.

Server-side rendering uses Node.js to render your pages in a background process; therefore, Node must be available on your server for server-side rendering to function properly.

## Laravel Starter Kits

If you are using [Laravel Breeze or Jetstream](https://laravel.com/docs/starter-kits), you may install the starter kit's scaffolding with Inertia SSR support pre-configured using the `--ssr` flag.

```bash theme={null}
php artisan breeze:install react --ssr
php artisan breeze:install vue --ssr
```

## Install Dependencies

If you are not using a Laravel starter kit and would like to manually configure SSR, we'll first install the additional dependencies required for server-side rendering. This is only necessary for the Vue adapters, so you can skip this step if you're using React or Svelte.

<CodeGroup>
  ```bash Vue 2 theme={null}
  npm install vue-server-renderer
  ```

  ```bash Vue 3 theme={null}
  npm install @vue/server-renderer
  ```

  ```js React icon="react" theme={null}
  // No additional dependencies required
  ```

  ```js Svelte icon="s" theme={null}
  // No additional dependencies required
  ```
</CodeGroup>

Then, make sure you have the latest version of the Inertia Laravel adapter installed.

```bash theme={null}
composer require inertiajs/inertia-laravel
```

## Add Server Entry-Point

Next, we'll create a `resources/js/ssr.js` file within our Laravel project that will serve as our SSR entry point.

```bash theme={null}
touch resources/js/ssr.js
```

This file is going to look very similar to your `resources/js/app.js` file, except it's not going to run in the browser, but rather in Node.js. Here's a complete example.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  import { createInertiaApp } from '@inertiajs/vue2'
  import createServer from '@inertiajs/vue2/server'
  import Vue from 'vue'
  import { createRenderer } from 'vue-server-renderer'

  createServer(page =>
      createInertiaApp({
          page,
          render: createRenderer().renderToString,
          resolve: name => {
              const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
              return pages[`./Pages/${name}.vue`]
          },
          setup({ App, props, plugin }) {
              Vue.use(plugin)
              return new Vue({
                  render: h => h(App, props),
              })
          },
      }),
  )
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  import { createInertiaApp } from '@inertiajs/vue3'
  import createServer from '@inertiajs/vue3/server'
  import { renderToString } from '@vue/server-renderer'
  import { createSSRApp, h } from 'vue'

  createServer(page =>
      createInertiaApp({
          page,
          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),
              }).use(plugin)
          },
      }),
  )
  ```

  ```jsx React icon="react" theme={null}
  import { createInertiaApp } from '@inertiajs/react'
  import createServer from '@inertiajs/react/server'
  import ReactDOMServer from 'react-dom/server'

  createServer(page =>
      createInertiaApp({
          page,
          render: ReactDOMServer.renderToString,
          resolve: name => {
              const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
              return pages[`./Pages/${name}.jsx`]
          },
          setup: ({ App, props }) => <App {...props} />,
      }),
  )
  ```

  ```js Svelte icon="s" theme={null}
  import { createInertiaApp } from '@inertiajs/svelte'
  import createServer from '@inertiajs/svelte/server'

  createServer(page =>
      createInertiaApp({
          page,
          resolve: name => {
              const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true })
              return pages[`./Pages/${name}.svelte`]
          },
      }),
  )
  ```
</CodeGroup>

When creating this file, 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.

## Setup Vite

Next, we need to update our Vite configuration to build our new `ssr.js` file. We can do this by adding a `ssr` property to Laravel's Vite plugin configuration in our `vite.config.js`file.

```js theme={null}
export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            ssr: 'resources/js/ssr.js', // [!code ++]
            refresh: true,
        }),
        // ...
    ],
})
```

## Update Npm Script

Next, let's update the `build` script in our `package.json` file to also build our new `ssr.js` file.

```json theme={null}
"scripts": {
    "dev": "vite",
    "build": "vite build" // [!code --]
    "build": "vite build && vite build --ssr" // [!code ++]
},
```

Now you can build both your client-side and server-side bundles.

```bash theme={null}
npm run build
```

## Running the SSR Server

Now that you have built both your client-side and server-side bundles, you should be able run the Node-based Inertia SSR server using the following command.

```bash theme={null}
php artisan inertia:start-ssr
```

With the server running, you should 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 still navigate around your application.

## Client Side Hydration

<ClientSpecific>
  Since your website is now being server-side rendered, you can instruct <VueSpecific>Vue</VueSpecific><ReactSpecific>React</ReactSpecific><SvelteSpecific>Svelte</SvelteSpecific> to "hydrate" the static markup and make it interactive instead of re-rendering all the HTML that we just generated.
</ClientSpecific>

<Vue2Specific>Inertia automatically enables client-side hydration in Vue 2 apps, so no changes are required.</Vue2Specific>

<Vue3Specific>To enable client-side hydration in a Vue 3 app, update your `app.js` file to use `createSSRApp` instead of `createApp`:</Vue3Specific>

<ReactSpecific>To enable client-side hydration in a React app, update your `app.js` file to use `hydrateRoot` instead of `createRoot`:</ReactSpecific>

<SvelteSpecific>To enable client-side hydration in a Svelte app, set the `hydratable` compiler option to `true` in your `vite.config.js` file:</SvelteSpecific>

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  // No changes required
  ```

  ```js Vue 3 theme={null}
  import { createApp, h } from 'vue' // [!code --]
  import { createSSRApp, h } from 'vue' // [!code ++]
  import { createInertiaApp } from '@inertiajs/vue3'

  createInertiaApp({
      resolve: name => {
          const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
          return pages[`./Pages/${name}.vue`]
      },
      setup({ el, App, props, plugin }) {
          createApp({ render: () => h(App, props) }) // [!code --]
          createSSRApp({ render: () => h(App, props) }) // [!code ++]
              .use(plugin)
              .mount(el)
      },
  })
  ```

  ```js React icon="react" theme={null}
  import { createInertiaApp } from '@inertiajs/react'
  import { createRoot } from 'react-dom/client' // [!code --]
  import { hydrateRoot } from 'react-dom/client' // [!code ++]

  createInertiaApp({
      resolve: name => {
          const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
          return pages[`./Pages/${name}.jsx`]
      },
      setup({ el, App, props }) {
          createRoot(el).render(<App {...props} />) // [!code --]
          hydrateRoot(el, <App {...props} />) // [!code ++]
      },
  })
  ```

  ```js Svelte icon="s" theme={null}
  import { svelte } from '@sveltejs/vite-plugin-svelte'
  import laravel from 'laravel-vite-plugin'
  import { defineConfig } from 'vite'

  export default defineConfig({
      plugins: [
          laravel.default({
              input: ['resources/css/app.css', 'resources/js/app.js'],
              ssr: 'resources/js/ssr.js',
              refresh: true,
          }),
          svelte(), // [!code --]
          svelte({ // [!code ++:5]
              compilerOptions: {
                  hydratable: true,
              },
          }),
      ],
  })
  ```
</CodeGroup>

<SvelteSpecific>
  You'll also need to enable hydration in your `app.js` file:

  ```js theme={null}
  import { createInertiaApp } from '@inertiajs/svelte'

  createInertiaApp({
      resolve: name => {
          const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true })
          return pages[`./Pages/${name}.svelte`]
      },
      setup({ el, App, props }) { // [!code --:3]
          new App({ target: el, props })
      },
      setup({ el, App }) { // [!code ++:3]
          new App({ target: el, hydrate: true })
      },
  })
  ```
</SvelteSpecific>

## Deployment

When deploying your SSR enabled app to production, you'll need to build both the client-side (`app.js`) and server-side bundles (`ssr.js`), and then run the SSR server as a background process, typically using a process monitoring tool such as Supervisor.

```bash theme={null}
php artisan inertia:start-ssr
```

To stop the SSR server, for instance when you deploy a new version of your website, you may utilize the `inertia:stop-ssr` Artisan command. Your process monitor (such as Supervisor) should be responsible for automatically restarting the SSR server after it has stopped.

```bash theme={null}
php artisan inertia:stop-ssr
```

## Laravel Forge

To run the SSR server on Forge, you should create a new daemon that runs `php artisan inertia:start-ssr` from the root of your app. Or, you may utilize the built-in Inertia integration from your Forge application's management dashboard.

Next, whenever you deploy your application, you can automatically restart the SSR server by calling the `php artisan inertia:stop-ssr` command. This will stop the existing SSR server, forcing a new one to be started by your process monitor.

## Heroku

To run the SSR server on Heroku, update the `web` configuration in your `Procfile` to run the SSR server before starting your web server.

```bash theme={null}
web: php artisan inertia:start-ssr & vendor/bin/heroku-php-apache2 public/
```

Note, you must have the `heroku/nodejs` buildpack installed in addition to the `heroku/php` buildback for the SSR server to run.
