Jetstream's Livewire vs Inertia Choice: What You're Actually Deciding
Jetstream's Livewire vs Inertia prompt isn't about UI taste — it decides where your rendering logic lives and how you test it. Here's how to choose with a concrete example.
09 Mar 2026, 01:36 UTC

When you run php artisan jetstream:install, the installer asks one question that shapes your whole frontend: Livewire or Inertia? The takeaway most teams miss: you're not picking a UI library, you're picking where your rendering logic lives and how you'll test it. Both stacks give you identical authentication, two-factor, team management, and API token features — the difference is everything that happens after the login screen.
What each stack actually is
The Livewire stack renders HTML on the server. Your components are PHP classes in app/Http/Livewire (or app/Livewire in newer versions) paired with Blade views. Interactivity — modals, form updates, dynamic lists — is handled by Livewire's wire protocol over AJAX, with Alpine.js sprinkled in for purely client-side behavior like dropdown toggles. You write almost no JavaScript.
The Inertia stack renders pages as Vue (or React) components in resources/js/Pages. Laravel controllers return Inertia::render() responses, and Inertia swaps page components client-side, giving a SPA feel without building a separate API. Laravel remains your only backend — no CORS, no token-based SPA auth to design.
The real decision: rendering and testing strategy
With Livewire, your tests stay in PHP. Livewire ships a testing helper that mounts a component, sets properties, calls methods, and asserts on state — no browser required for most coverage:
// tests/Feature/CreateTeamTest.php — run with: php artisan test
use App\Models\User;
use Laravel\Jetstream\Http\Livewire\CreateTeamForm;
use Livewire\Livewire;
public function test_teams_can_be_created(): void
{
$this->actingAs($user = User::factory()->create());
Livewire::test(CreateTeamForm::class)
->set(['state' => ['name' => 'Acme Corp']])
->call('createTeam');
$this->assertCount(1, $user->fresh()->ownedTeams);
$this->assertEquals('Acme Corp', $user->fresh()->ownedTeams->first()->name);
}Run this with php artisan test from your project root — no special permissions needed. The check that matters: the assertion on ownedTeams proves the component's action actually persisted, not just that validation passed.
With Inertia, the equivalent coverage splits in two. PHP feature tests assert the controller returned the right Inertia page and props (using AssertableInertia), but anything interactive — a form's client-side validation, a Vue component's emitted events — needs Vitest/Jest component tests or a browser tool like Dusk or Playwright. That's a second test toolchain, a second CI step, and a second set of version constraints to keep green.
Where each stack bites you
Livewire's weakness is JavaScript interop. Because Livewire re-renders DOM fragments after each round trip, third-party JS libraries (rich text editors, date pickers, chart widgets) can lose their initialized state or double-bind. You end up learning wire:ignore, Livewire's hook system, and careful element targeting — the "no JavaScript" promise quietly becomes "some JavaScript, in awkward places."
Inertia's weakness is dependency drift. Your package.json now carries Vue/React, the Inertia client adapter, Vite, and Jetstream's JS assumptions. A mismatched @inertiajs/vue3 and server-side inertiajs/inertia-laravel version can produce confusing runtime errors at compile or navigation time. You also take on real frontend concerns: bundle size, hydration, component state management.
A practical way to choose
Ask two questions. First: who maintains the UI? If your team is backend-heavy and features are CRUD-shaped — dashboards, admin panels, internal tools — Livewire keeps everything in one language and one test suite, and you'll ship faster. Second: does the product need genuinely rich client-side interaction — drag-and-drop boards, real-time collaborative editing, complex form wizards? If yes, Inertia plus Vue/React is the honest choice; forcing that into Livewire creates more glue code than it saves.
Either way, verify the generated structure before committing. After installing, check composer.json and package.json for the expected dependencies (livewire/livewire vs inertiajs/inertia-laravel plus the client adapter), confirm whether components landed in app/Livewire or resources/js/Pages, and run one real CRUD flow end to end. The stack you pick on day one is cheap to install and expensive to migrate — spend an hour prototyping the riskiest screen in your app before you decide.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.