Server-side rendering
Lattice works with Inertia SSR: the first visit is rendered to full HTML on the server and the client hydrates it in place. Same pages, same components — SSR is a deployment choice, not a different way of building.
The SSR entry
Section titled “The SSR entry”@inertiajs/vite normally generates the SSR bootstrap by detecting a literal createInertiaApp
call — which a Lattice app doesn’t have. The package ships the equivalent for createLatticeApp:
createLatticeSsr, on its own @lattice-php/lattice/ssr subpath. Create resources/js/ssr.tsx
next to your app.tsx and pass it the same options:
import createServer from "@inertiajs/react/server";import { createLatticeSsr } from "@lattice-php/lattice/ssr";import plugins from "virtual:lattice/plugins";import sprite from "virtual:svg-sprite";
createServer( createLatticeSsr({ plugins, sprite, pages: import.meta.glob("./Pages/**/*.tsx"), }),);@inertiajs/vite finds resources/js/ssr.tsx on its own and rewrites the createServer call into
the development endpoint and the production HTTP bootstrap — one file covers both. Keep the options
in sync with createLatticeApp (or
extract them into a shared module); browser-only options such as boot never run on the server, so
sharing one options object is safe.
Development
Section titled “Development”Nothing else to start. With the entry in place and inertia.ssr.enabled on (the default), the
Laravel adapter renders through the Vite dev server directly — no separate Node process.
Production
Section titled “Production”Build the SSR bundle alongside the client build and run the SSR server. With the Laravel Vite
plugin, point its ssr option at the same entry so vite build --ssr emits
bootstrap/ssr/ssr.mjs where the adapter expects it:
laravel({ input: ["resources/css/app.css", "resources/js/app.tsx"], ssr: "resources/js/ssr.tsx",}),vite build && vite build --ssrphp artisan inertia:start-ssrWhat the server renders
Section titled “What the server renders”- The full page — layout, navigation, and every eagerly registered component. Components registered
with
lazyComponent()render their loading fallback on the server and stream in after hydration; register a component witheagerComponent()if its markup should be part of the server HTML. - The theme. Lattice shares the
appearancecookie with the server render, so a user who picked dark mode gets dark-mode HTML instead of a flash of the default. bootand the rest of the client bootstrap run after hydration. On a server-rendered page the first client render intentionally does not wait for them — hydration must match the HTML the server produced.
SSR-safe custom components
Section titled “SSR-safe custom components”Anything you register yourself (custom fields, component packages) renders on the server too. Two rules keep a component SSR-safe:
- Don’t touch
window,document, or other browser globals during render — move that work into an effect, or guard it withtypeof window === "undefined". - Import
useLayoutEffectfrom@lattice-php/ui/lib/use-layout-effectinstead ofreact. It is the same hook in the browser and substitutesuseEffecton the server, where React’s ownuseLayoutEffectwarns.