Same routes, same controllers. The delivery mechanism changed underneath them.
84 pages migrated from Blade + Livewire to Inertia.js + React, one page at a time,
with both stacks running side by side until each page was fully converted, tested,
and verified — never a big-bang rewrite. The request still lands on the same
routes/web.php entry and the same controller either way.
Before
Blade + Livewire
Browser
full page GET
→
Route + Controller
ProjectController::index
→
Blade view
renders a Livewire component
→
Livewire runtime
wire:click → AJAX → same Blade template, re-rendered server-side
Response: full HTML document, then server-rendered partials for every interaction
After
Inertia.js + React
Browser
Inertia visit, XHR
→
Route + Controller
ProjectController::index
→
Inertia::render()
component name + props, as JSON
→
React component
renders client-side, pushState — no reload
Response: JSON props on navigation, real DOM diffing for every interaction
84 / 84
pages converted, page by page — both stacks coexisted the whole time
0
new API endpoints written — controllers kept returning props, not a separate JSON API
1
thing that never moved: auth, sessions, and CSRF, unchanged on both sides
Why this shape, not a decoupled SPA: a fully separate API would have meant
designing and versioning an entire API surface before migrating even one page. Inertia let
each page keep using its existing controller almost unchanged — the trade was giving up
independent deployability and a reusable API layer a future non-web client could have consumed.