Livewire 3 Upgrade check — check upgrade blockers free

Finds Livewire 2 APIs that silently die in Livewire 3 — emit(), wire:model.defer, dispatchBrowserEvent, livewire:load, missing :key — in your .php and .blade.php files. Runs entirely in your browser — nothing is uploaded.

Same engine as the VS Code extension, byte for byte.

Install free

Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.

VS Code MarketplaceOpen VSX (Cursor, VSCodium)npmMCP server (npx)Docker Hub
ext install ReadyStack.livewire3-upgrade-blocker-lint
npx @readystack/livewire3-upgrade-blocker-lint <file>
npx @readystack/livewire3-upgrade-blocker-lint --mcp

Team? One key for every ReadyStack linter, 5 seats, $149 once

Get the full rule table as a PDF
All 15 rules Livewire 3 Upgrade Blocker Lint checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.

Get the full version $29

Scan every .php and .blade.php in the workspace in one command and export an owned REPORT.md / JSON with file:line for the whole migration, plus a non-zero exit code for CI.

One payment, one licence key for this tool. The key is shown right after payment.

A freelance Laravel developer at $85/hour spends the opening hours of an upgrade making this inventory by hand

Buy the full version — $29
ENDEJAESPT

Find a tool

· ReadyStack

Worked example

Real numbers from this tool, line by line.

Livewire 3 Upgrade Blocker Lint

Fourteen blockers - 10 errors and 4 warnings - inside one 43-line Livewire 2 component: that is what a Laravel developer maintaining a Livewire 2 app sees on the very first file this linter reads. Audited 2026-09-18, the same component rewritten for Livewire 3 reports zero.

That number is invisible without a tool because of the shape of the break. It is not a build failure: Blade compiles, the page renders, the layout is identical - and then a button does nothing and a search box stops filtering.

Four of the fourteen are event calls. $this->emit('invoiceSaved') is gone in Livewire 3; the method name is dispatch. PHP does not care until that line executes, so the failure waits for whichever user presses Save first. $this->emitTo('billing.totals', 'refresh') becomes $this->dispatch('refresh')->to(...). emitUp and emitSelf are gone too - events bubble by default - and dispatchBrowserEvent folds into the same dispatch.

Six are in the template, and these are the quiet ones. wire:model.defer is not an error in Livewire 3 - plain wire:model is already deferred, so the modifier is simply ignored. wire:model.lazy became wire:model.blur. wire:model.debounce.400ms is the worst of the set: debounce now applies only to live bindings, so without .live the input sends nothing at all and the field looks like a plain text box. wire:click.prefetch has no replacement, @livewireStyles is gone, and livewire:load is now livewire:init - so every Alpine component registered inside that listener silently never initialises.

The last five sit on the component surface. protected $queryString is replaced by the #[Url] attribute per property, so the array is read as an ordinary property and the URL quietly stops syncing. Livewire 3 discovers components in App\Livewire, not App\Http\Livewire, and the .defer suffix on $wire.entangle() is gone. assertEmitted is now assertDispatched, so a test on the old name fails as an undefined method - a green suite that never checked the event. And a <livewire:row> tag inside @foreach now needs :key; without it the DOM diff reuses the wrong child component, so after a delete row 3's state appears on row 4.

That last rule is why grep -r "emit(" is not the answer: the defect is not a string that is present but an attribute that is absent inside a block, which needs the loop depth a line-oriented search never tracks. Same for debounce: wire:model.debounce is dead, wire:model.live.debounce is correct, and one is a prefix of the other.

Staying put is not a neutral option. Livewire 2 caps the application at Laravel 10, whose security support ended 2025-02-04. Every month on v2 is a month on an unsupported framework version, and the list above is the toll booth.

The extension is 15 rules over **/*.php, which includes .blade.php. Blade {{-- --}} and PHP comments are stripped before matching, so a migration note mentioning emit() is not reported, and the matching is local. Free: the file you have open, every blocker with its v3 replacement, no watermark and no run cap. Paid, a different axis: every .php and .blade.php in the workspace in one command, exported as a REPORT.md or JSON with file:line you keep, plus a non-zero exit code for CI.

A freelance Laravel developer at $85 an hour spends the opening hours of any upgrade building this inventory by hand. The same engine, the same rules.json, also runs on one browser page with nothing installed - paste a component, read the fourteen.

15 seconds — what it actually does

Questions people ask

What does Livewire 3 Upgrade Blocker Lint actually do?

It reads your .php and .blade.php files and flags the Livewire 2 lines that stop working under Livewire 3, printing the v3 replacement next to each one. Fifteen rules cover events, Blade modifiers and the component surface. On the 43-line Livewire 2 component shipped with it, the engine reports 14 blockers: 10 errors and 4 warnings.

Who is this for?

Laravel developers who own an app still running Livewire 2 and are doing, planning or reviewing the move to Livewire 3 — including anyone reviewing Livewire code an assistant generated, which is often written against the Livewire 2 API. Agencies inheriting a client Laravel app use it as the first pass before quoting the upgrade.

Why is grep or the upgrade guide not enough?

Grep finds emit( and wire:model.defer. It cannot find a <livewire:row> inside @foreach that is missing :key, because that defect is a missing attribute inside a block and needs loop depth. It also cannot separate wire:model.debounce, which is dead in v3, from wire:model.live.debounce, which is correct, since one string contains the other.

What is free and what needs a licence key?

Free and unlimited: scan the file you have open and get every blocker with its Livewire 3 replacement, line by line. That finishes that file, with no watermark and no run cap. The licence key adds a different job: scanning every .php and .blade.php in the workspace at once and exporting a REPORT.md or JSON with file:line, plus a CI exit code.

What would this cost me otherwise?

A freelance Laravel developer at $85 an hour spends the first hours of any Livewire upgrade making exactly this inventory by hand, component by component. The extension is $29 once, with one licence key per person or team seat and. The free tier covers a single file without paying anything.

Why not just ask ChatGPT or another AI chat?

A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Livewire 3 Upgrade Blocker Lint checks the file you open against 15 rules from a rule set dated 2026-09-20, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files.

Ask about this tool

One question, answered by the person who built it. Your email only if you want the answer sent.

Embed this tool on your site (free)

Paste this code into your page. It runs in your visitor’s browser and stays up to date. Nothing your visitors type is stored.

 All embeddable tools

For businesses: your name and logo instead of ours, and each visitor’s result + e-mail in your inbox (only when they tick consent) — Pro from $19/month. See Pro →