The problem: After upgrading Livewire to v3, some Alpine.js components (x-data blocks, dropdowns, modals) stop initializing on pages that get updated by Livewire — they just sit there dead, no console error, no reaction to clicks.
Environment: Laravel 10/11, Livewire 3.x, Alpine.js 3.x installed separately via npm, Vite 5, resources/js/app.js bundling both.
The Error
Alpine Warning: Detected multiple instances of Alpine running
Alpine Warning: Alpine has already been initialized on this page.
Ignoring duplicate script tag/import.
You'll usually only see this if you have DevTools console open at the exact moment the page loads — after that, the components just look broken with no further logging.
Why It Happens
Since Livewire 3, Livewire ships its own bundled copy of Alpine.js internally. You don't need to install Alpine yourself anymore for Livewire to work — it's already inside livewire.js.
The problem is that most Laravel + Vite starter setups (and a lot of older tutorials) still have this in app.js:
Now you have two separate Alpine instances running on the same page: Livewire's internal one, and your manually imported one. Whichever one starts second refuses to take over — so any Alpine component that Livewire's morph step touches (i.e. anything inside a Livewire component that re-renders) ends up bound to the "wrong" instance and never gets re-initialized after an update. That's why it looks like Alpine "randomly" stops working specifically after a Livewire update, and why static Alpine components outside any Livewire component keep working fine.
The Fix
Stop importing Alpine yourself. Let Livewire's bundled Alpine be the only instance on the page.
Remove this from app.js completely:
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
If you also register custom Alpine components with Alpine.data(), hook into Livewire's Alpine instance instead using the alpine:init event, which fires on the Alpine instance Livewire actually starts:
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
open: false,
toggle() {
this.open = !this.open;
}
}));
});
Then make sure your Blade layout loads Livewire's assets (which bring Alpine along with them) and nothing else touches Alpine directly:
<head>
@vite(['resources/css/app.css', 'resources/js/app.js'])
@livewireStyles
</head>
<body>
...
@livewireScripts
</body>
Run npm uninstall alpinejs if nothing else in your bundle needs it directly, so it can't accidentally get re-imported later.
Step-by-Step
- Open
resources/js/app.jsand delete anyimport Alpine from 'alpinejs',window.Alpine = Alpine, andAlpine.start()lines. - Run
npm uninstall alpinejsif no other JS in your project imports it directly. - Move any
Alpine.data(...),Alpine.store(...), orAlpine.directive(...)calls inside adocument.addEventListener('alpine:init', () => { ... })block. - Confirm your Blade layout includes
@livewireScriptsbefore</body>and that it isn't duplicated on the page (check both your main layout and any partials). - Rebuild assets with
npm run build(or restartnpm run dev) and hard-refresh with cache disabled. - Open DevTools console on load — the "multiple instances" warning should be gone.
- Trigger a Livewire update (e.g. a
wire:modelchange orwire:click) and confirm Alpine components inside that component still respond afterward.
Alpine.start() internally. Two packages doing this independently will reproduce the exact same warning even after you've removed your own manual import — check node_modules for other alpinejs imports if the warning persists after step 1–3.Still seeing this after checking your bundle? Reach out on the Contact page and I'll help you trace it.