Comparisons

How reactolith stacks up against the other ways to drive a React frontend from a server-rendered backend.

reactolith lives in the same neighbourhood as Inertia.js, Hotwire Turbo and htmx. They all share the same instinct: keep the backend in charge of routing, templates, permissions and URLs, and stop maintaining a parallel SPA + JSON API. Where they differ is in what crosses the wire, and what happens to the existing client tree on every visit.

Side-by-side

  reactolith Inertia.js Hotwire Turbo htmx
Wire format HTML JSON page props HTML HTML fragments
UI library React React, Vue, Svelte None (vanilla + Stimulus) None (vanilla)
Page navigation Morph React tree in place Replace page-level component Morph DOM in place Swap a fragment
Component state across nav Preserved Reset (page component is swapped) Preserved (DOM-level) Preserved outside the swapped fragment
Need a new backend layer? No — existing controllers + templates Yes — an Inertia adapter that returns page props No No
Real-time updates Mercure SSE → same render path Manual / external Turbo Streams over WebSocket/SSE SSE / WebSocket extensions

Pick a deeper dive

  • reactolith vs Inertia.js — the React/Vue/Svelte adapter for “classic” backends. Where it shines, what it gives up by replacing the page component, and what reactolith does differently.
  • reactolith vs Hotwire Turbo — same backend-driven philosophy, but reactolith brings the morph idea to a React component tree instead of plain DOM.

Why this neighbourhood matters

The Inertia / Turbo / htmx / reactolith family exists for one reason: most teams don’t want to be running two apps. A Rails / Symfony / Laravel / Django app and a React SPA glued to it via a JSON API is a lot of duplicated work — routing twice, validation twice, auth twice, URL helpers twice, deployments twice. DHH made the architectural case for collapsing all of that back into one codebase in “The Majestic Monolith”.

Turbo and htmx make that monolith viable for vanilla DOM. Inertia makes it viable for React/Vue/Svelte at the cost of a JSON page-prop boundary. reactolith makes it viable for React without that boundary — the wire format stays HTML, and the React tree morphs in place across every navigation.