There is a moment in many Laravel projects when Blade stops scaling: a growing interface needs real-time behaviour, optimistic updates and component reuse that Blade partials and a drawer full of jQuery can no longer carry. The good news — you do not rewrite the app. Inertia.js was designed for exactly this migration: same Laravel backend, same routes, same auth, a React interface introduced module by module.
The migration principle: one module at a time
A big-bang rewrite is how projects die. The Inertia migration runs like a renovation of a lived-in house — one room at a time, everything else keeps working:
- Install Inertia in the existing app (three Composer/npm packages, one middleware).
- Build the React shell — a persistent layout (navigation, user menu) shared by all future Inertia pages.
- Pick the first module with the highest value-to-risk ratio: usually a screen users complain about, not the most critical one.
- Convert that module's controller methods from
view()toInertia::render(). - Move the Blade markup into React components — structure first, behaviour later.
- Repeat. Blade routes stay alive for months if needed.
What the migration actually touches
| Layer | What changes |
|---|---|
| Routes | Nothing — same URLs, same names |
| Controllers | return view(...) becomes Inertia::render(...) with props |
| Models, policies, validation | Nothing |
| Blade views | Replaced per module by React components |
| JavaScript | The old sprinkle scripts die with the Blade they belonged to |
| Authentication | Nothing — sessions, middleware and guards are untouched |
That is the whole trick of the Inertia approach: the backend contract is already the Laravel app itself. There is no API to design and no token layer to add — the reasoning behind that is in Inertia.js with Laravel and React — SPA without a separate API.
Step by step
Install and scaffold
composer require inertiajs/inertia-laravel
npm install @inertiajs/react react react-dom
php artisan inertia:middleware
A controller method before and after
// before
public function index(Request $request)
{
return view('orders.index', [
'orders' => Order::paginate(25),
'filters' => $request->only(['status', 'search']),
]);
}
// after — same data, a React page instead of a Blade view
public function index(Request $request)
{
return Inertia::render('Orders/Index', [
'orders' => OrderResource::collection(Order::paginate(25)),
'filters' => $request->only(['status', 'search']),
]);
}
Keep the Blade view in the repository until the module is signed off — switching a route back is one line. During the dual-stack period, links between migrated and unmigrated modules work like any normal page load; users never see the seam.
The traps that stall migrations
Warning: Do not convert the whole data layer to API resources in one pass. Inertia props can serialize Eloquent models directly; introduce resources (as above) only where the payload shape matters — usually for tables and forms.
- Design drift. While Blade and React coexist, both need the same design tokens. Extract the design system into Tailwind classes shared by both stacks before starting.
- Forms first, widgets later. Forms carry business value; charts and dashboards can wait. And forms in Inertia have their own patterns worth learning early.
- No tests on the seam. Keep Laravel feature tests running against the same URLs — they catch regressions whether the route renders Blade or React.
- Migrating auth screens first. Login and registration feel tempting (they are simple) but they carry the most risk. Do them in the middle of the schedule, not at the start.
What you end up with
After the last module, the codebase is a single-repo SPA: Laravel routing and sessions, React interface, one deployment. Teams that want the safety net can keep Blade for internal pages indefinitely — plenty of our clients run React for the product and Blade for legal and marketing pages that change once a year.
If you would rather hand the migration to a team that has done it before, see Laravel development services — we scope migrations per module after a short audit.
FAQ
Can I migrate from Blade to Inertia.js incrementally?
Yes — Inertia and Blade coexist in one app. Routes render one or the other independently, so the app works after every migration step.
How much of the backend changes?
Very little. Controllers, models, validation and policies stay; view() becomes Inertia::render() with props.
How long does it take?
It depends on screens, not code size: a 5–10 screen module is typically 2,000–8,000 PLN net and 1–3 weeks, including React components and tests.
👉 Planning a Blade-to-Inertia migration? Check our Laravel development services or hire a Laravel developer for a module-by-module migration plan.
📖 Read more: Inertia.js with Laravel and React, forms and validation in Inertia.js and Inertia.js vs Livewire.