Inertia.js SSR vs Client-Only Rendering: A Laravel + Vue Decision Guide
Deciding between Inertia.js SSR and client-only rendering in Laravel + Vue? Compare setup cost, SEO impact, and hydration risks, then validate with a concrete SSR configuration.
21 May 2026, 04:01 UTC

The decision: SSR or client-only for your Inertia app
If your Laravel + Vue application serves content-heavy pages where search-engine visibility and first-paint speed matter, you face a choice: let the server render the initial HTML through Inertia’s server-side rendering (SSR) adapter, or ship a client-only app that builds the page after JavaScript loads. The useful takeaway is that SSR eliminates the blank-screen gap and puts real markup in the page source, but it adds a second server process, stricter component rules, and—critically—SSR support has been treated as experimental, so you must verify current stability before committing.
Comparing the two rendering modes
| Factor | Client-Only Rendering | Inertia SSR |
|---|---|---|
| Initial HTML | Empty root element; browser builds DOM after JS executes | Fully rendered markup delivered on first response |
| SEO / crawlers | Depends on JavaScript execution | Markup present in raw page source |
| Setup | Works with any Inertia adapter out of the box | Requires @inertiajs/server and a running Node process |
| Server cost | Low; PHP returns JSON, Vue renders in browser | Higher CPU per request; Node renders markup alongside PHP |
| Component constraints | None specific to rendering mode | Components must avoid browser-only APIs during render or risk hydration mismatches |
| Stability | Stable, default path | Marked experimental in documentation; verify per version |
What SSR actually adds to your stack
In a client-only Inertia app, Laravel returns a JSON payload and the Vue adapter mounts into an empty <div>. Users see a blank page until the bundle downloads and executes. SSR changes this by running the same Vue components in a Node process during the initial request, so the browser receives HTML it can paint immediately. Vue then “hydrates” that markup—attaching event listeners and reactivity to the existing DOM rather than recreating it.
The trade-off is operational. You now maintain a second long-running service (the Node SSR server) next to PHP-FPM or your Laravel Octane worker. Every page view costs CPU in both tiers. In return, you can reduce time-to-interactive for content-heavy routes and avoid relying on search-engine crawlers to execute JavaScript. If your app is a highly interactive dashboard behind authentication, the SEO benefit is small and the added complexity may not pay off.
Concrete implementation: enabling SSR in Laravel + Vue
The following steps assume a Laravel project already using inertia-laravel and the Vue 3 adapter. Because SSR is experimental, treat exact method names and file paths as items to verify against your installed package versions before deploying.
1. Install the SSR adapter
Run in your project root (the directory containing package.json):
npm install @inertiajs/server @inertiajs/vue3
This adds the Node-side renderer. If @inertiajs/vue3 is already present, npm will simply ensure versions align.
2. Enable SSR in Laravel
In a service provider—commonly app/Providers/AppServiceProvider.php—call the SSR toggle during boot:
use Inertia\Inertia;
public function boot()
{
Inertia::setServerSideRenderingEnabled(true);
}
You need write access to the provider file and the ability to clear config cache afterward if you use it. After editing, run:
php artisan config:clear
Expected check: no boot errors when loading any Inertia page.
3. Start the SSR server process
SSR requires a Node entry point that imports your Vue app and renders it to a string. In many Laravel setups this is a file such as resources/js/ssr.js or resources/js/ssr.ts, but confirm the path your scaffolding expects. Start it in a separate terminal or under a process manager:
node resources/js/ssr.js
Keep this process alive in production with a supervisor (systemd, Supervisor, or a container orchestrator). If the Node process dies, Inertia will fall back to client-only rendering for new requests, but you will lose the SSR benefit until it restarts.
4. Make components SSR-safe
During the server render, window, document, and other browser globals do not exist. Guard them or defer access to onMounted:
<script setup>
import { onMounted, ref } from 'vue'
const width = ref(0)
onMounted(() => {
width.value = window.innerWidth
})
</script>
Components that read browser APIs during setup or render will throw or produce mismatched HTML.
Validating the result
After starting both the Laravel server and the Node SSR process, load a page in your browser and view the raw source (right-click → View Page Source, or curl http://your-app.test/your-page). If SSR is active, you should see your component’s markup—headings, lists, text—inside the Inertia root element before any JavaScript executes. If you only see an empty <div id="app">, the Node process is not connected or SSR is disabled.
Open Chrome DevTools and check the Console for hydration warnings. A message such as “Hydration node mismatch” indicates the server-rendered HTML differs from what Vue expects on the client, usually because of browser-only code or non-deterministic output (random values, Date.now()). Fix the component so both renders produce identical markup.
To compare performance, use the DevTools Performance tab to record page loads in both modes. Look at First Contentful Paint and Time to Interactive. Do not rely on a single cold run; network and CPU throttling will change the numbers.
Limitations and rollback
SSR is not a universal win. It increases infrastructure complexity, doubles the rendering surface for bugs, and remains experimental in the Inertia ecosystem. Applications that are entirely behind login, heavily interactive, or served to users on fast connections may see little benefit.
If you decide to revert, the operation does change state. Set Inertia::setServerSideRenderingEnabled(false) in the provider, run php artisan config:clear, and stop the Node SSR process. Remove the @inertiajs/server dependency with npm uninstall @inertiajs/server if you no longer need it. Verify afterward that pages still render client-only and that no deployment scripts expect the Node process to be running.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.