Leveraging Inertia.js Server‑Side Rendering with React: Setup, Example, and Trade‑offs
Inertia.js lets you render React components on the server, improving first‑paint and SEO. This guide shows how to set up SSR in Laravel, verifies it works, and weighs the trade‑offs you’ll face in production.
09 Mar 2026, 13:03 UTC

Why Server‑Side Rendering Matters for Inertia‑React Apps
When an Inertia route is requested, the client normally receives a lightweight JSON payload and then hydrates a React component tree. That extra round‑trip can hurt first‑paint times on slow networks, SEO crawlers, and users with JavaScript disabled. Inertia’s SSR support lets you send a fully rendered HTML string in the initial response, so the browser can display content immediately while still enjoying a single‑page‑app feel. The key is that the same React tree is used on both the server and the client, keeping hydration logic simple.
Setting Up SSR in a Laravel + React Project
1. Install Inertia and the React Adapter
# Run inside your Laravel project root
composer require inertiajs/inertia-laravel
npm install @inertiajs/inertia @inertiajs/inertia-react react react-dom
After installing, publish the Inertia configuration if you need custom options:
php artisan vendor:publish --tag=inertia-config
2. Add a Server‑Side Render Function
In app/Http/Middleware/HandleInertiaRequests.php, override render to provide a custom server‑side rendering callback. The callback receives the request, the component name, and the props.
public function render($request, $page)
{
return Inertia::render($page['component'], $page['props'], function () use ($request, $page) {
// Provide a Node.js‑based render function
return function ($component, $props) {
// Path to the Node build that exports a React component tree
$reactEntry = base_path('resources/js/entry-server.jsx');
// Use a simple wrapper that requires the component and renders it
$serverRender = function ($component, $props) use ($reactEntry) {
$module = require($reactEntry);
return ReactDOMServer::renderToString(
$module['default']($component, $props)
);
};
return $serverRender($component, $props);
};
});
}
In practice you’ll replace the inline require logic with a bundled Node script (e.g., built with Webpack or Vite) that exports a function returning the React tree.
3. Create a Simple React Component
Place a component in resources/js/Pages/Dashboard.jsx:
import { useEffect } from 'react';
export default function Dashboard({ time }) {
useEffect(() => {
console.log('Client‑side props:', time);
}, []);
return (
Dashboard
The server rendered this at: {time}
);
}
4. Define a Route That Uses Inertia
Add a route in routes/web.php:
use Inertia\Inertia;
Route::get('/dashboard', function () {
return Inertia::render('Dashboard', [
'time' => now()->toIso8601String(),
]);
});
When you visit /dashboard, Laravel will call the middleware, which will invoke the Node renderer and embed the resulting HTML inside the Inertia response. The client receives the same component tree and props, so hydration is straightforward.
Verifying SSR Works Correctly
- Inspect the page source. The first
<div id="app">should contain the rendered<h1>and<p>tags, not just a placeholder. - Check the console. Open DevTools and reload the page. You should see
Client‑side props: …logged, confirming the same data is passed to the client. - Measure first‑paint. In Chrome DevTools’ Performance panel, record a load of
/dashboardwith and without SSR. The SSR page typically shows a lower First Paint (FP) and First Contentful Paint (FCP). - Validate payload size. In the Network tab, the XHR that loads the page should carry only a small JSON payload (the props). The server‑rendered HTML is embedded in the response body, not transmitted separately.
Trade‑offs and Limitations
- Node.js Requirement. SSR can only run where a Node runtime is available. Deployments that support only PHP (e.g., certain shared hosts) cannot use SSR and will fall back to client‑side hydration.
- Payload Size. Inertia serializes props as JSON. Large data sets can inflate the payload, offsetting SSR’s performance gains. Pagination or lazy‑loading is recommended for heavy data.
- Hydration Mismatches. The component name used on the server must match the client bundle. A typo or missing export will result in a blank component after hydration.
- Code Duplication. The server bundle must include the same component tree the client uses. Keeping shared logic in a separate package helps avoid duplication but adds a build step.
- Debugging Complexity. Errors that occur only on the server (e.g., missing environment variables) can be harder to trace than client‑side errors because they surface during the initial request.
When to Opt In for SSR
Consider SSR if:
- Your audience includes users on low‑bandwidth connections or older devices.
- Search engine optimization is critical and you want crawlers to see fully rendered markup.
- First‑paint performance is a key metric for your product.
Skip SSR if:
- You’re targeting a single‑page‑app with a very small bundle and fast network.
- Your hosting environment cannot run Node.js.
- Your data payloads are large and you prefer to stream them client‑side.
Next Steps
- Set up a minimal SSR pipeline as shown above.
- Measure performance in your own environment.
- Profile the server render time; if it exceeds 200 ms, consider code‑splitting or moving heavy logic to the client.
- Gradually migrate more routes to SSR, keeping an eye on payload size and hydration logs.
- When ready, deploy to a Node‑capable environment (e.g., Docker with Node and PHP side‑by‑side) to keep SSR functional.
With a clear understanding of the trade‑offs, you can make an informed decision about whether Inertia’s SSR feature will deliver the performance gains your users need.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.