Laravel 12 Livewire 3 Setup Guide 2025: Complete Installation Tutorial
Welcome to 2025, where Laravel 12 has just arrived (released February 24, 2025) with enhanced support for Livewire 3, making it easier than ever to build dynamic, reactive web applications without touching JavaScript! If you're looking to harness the power of Laravel 12 with Livewire 3, you've come to the right place.
This comprehensive guide walks you through every step of setting up Laravel 12 with Livewire 3 . Whether you're starting a fresh project or integrating Livewire into an existing Laravel 12 application, this tutorial covers everything you need to know. Let's dive into building modern, reactive interfaces the Laravel way!
What's New : Laravel 12 introduces official starter kits with Livewire 3 and Flux UI, zero breaking changes for seamless upgrades, and enhanced performance optimizations. Alpine.js is now fully integrated by default!
What is Laravel 12?
Laravel 12, released on February 24, 2025, is a maintenance release that focuses on stability, security, and developer experience improvements. Unlike previous major versions, Laravel 12 introduces zero breaking changes, making it one of the smoothest upgrades in Laravel's history.
Key Features of Laravel 12:
- Zero Breaking Changes: First major Laravel version with no breaking changes - upgrade with confidence!
- New Official Starter Kits: Pre-configured kits for React, Vue, and Livewire 3 with modern UI frameworks
- PHP 8.2 - 8.4 Support: Full compatibility with the latest PHP versions
- Enhanced Performance: Improved memory management and database query optimizations
- Symfony 7 Upgrade: Built on the latest Symfony components for better stability
- Laravel Cloud Ready: Optimized for the upcoming Laravel Cloud platform
What is Livewire 3?
Laravel Livewire 3 is a full-stack framework that revolutionizes how you build dynamic interfaces in Laravel. Instead of writing Vue.js or React components, you build reactive interfaces entirely in PHP using familiar Blade syntax.
Why Choose Livewire 3 ?
- Pure PHP Development: Build reactive UIs without writing JavaScript
- Real-Time Updates: Components update dynamically without page refreshes
- Alpine.js Integration: Built-in Alpine for progressive enhancement
- Laravel Native: Uses familiar Laravel patterns - controllers, validation, authorization
- Faster Development: Ship features faster without context-switching between languages
- SEO Friendly: Server-side rendering by default
- Reduced Complexity: No API layer needed, no state management headaches
Prerequisites for Laravel 12 & Livewire 3 Setup
Before starting your Laravel 12 Livewire journey, ensure your development environment meets these requirements for 2025:
System Requirements:
- PHP Version: PHP 8.2, 8.3, or 8.4 (recommended: PHP 8.3)
- Composer: Latest version (2.7+)
- Node.js: Version 18+ (for asset compilation, optional)
- Database: MySQL 8.0+, PostgreSQL 12+, or SQLite
- Web Server: Apache, Nginx, or Laravel Valet
Check Your PHP Version:
php -v
# Output should show PHP 8.2.0 or higher
composer --version
# Ensure Composer 2.7+ is installedStep 1: Install Laravel 12
Let's start by creating a fresh Laravel 12 project. Laravel provides multiple installation methods , but the official Laravel installer is the recommended approach.
Method 1: Using Laravel Installer (Recommended)
First, ensure you have the latest Laravel installer:
# Install or update Laravel installer globally
composer global require laravel/installer
# Create a new Laravel 12 project
laravel new livewire-app
# Navigate to your project
cd livewire-appMethod 2: Using Composer Create-Project
# Create Laravel 12 project with Composer
composer create-project laravel/laravel livewire-app
cd livewire-appVerify Laravel Installation
# Check Laravel version
php artisan --version
# Should display: Laravel Framework 12.x.x
# Test the installation
php artisan serveVisit http://localhost:8000 in your browser - you should see the Laravel welcome page!
Step 2: Install Livewire 3 in Laravel 12
Installing Livewire 3 in Laravel 12 is straightforward. Livewire is fully compatible with Laravel 12 and requires zero additional configuration to get started.
Install via Composer
# Install Livewire 3
composer require livewire/livewireThat's it! Livewire 3 is now installed and ready to use. The package automatically registers its service provider, so no manual configuration is needed.
Verify Livewire Installation
Check your composer.json file to confirm Livewire was added:
{
"require": {
"php": "^8.2",
"laravel/framework": "^12.0",
"livewire/livewire": "^3.0"
}
}2025 Update: Laravel 12 automatically includes Alpine.js through Livewire 3. No separate installation needed - everything works seamlessly out of the box!
Step 3: Using Laravel 12 Official Starter Kits (Optional)
New in Laravel 12! Official starter kits provide pre-configured authentication scaffolding with Livewire 3, Tailwind CSS, and Flux UI. This is the fastest way to get a production-ready application.
Install Laravel Breeze with Livewire Stack
# Install Laravel Breeze
composer require laravel/breeze --dev
# Install Breeze with Livewire stack
php artisan breeze:install livewire
# Install dependencies and build assets
npm install
npm run dev
# Run migrations
php artisan migrateWhat You Get with Breeze Livewire Stack:
- ✅ Complete authentication system (login, register, password reset)
- ✅ Livewire 3 components pre-configured
- ✅ Tailwind CSS integration
- ✅ Flux UI components
- ✅ Profile management
- ✅ Email verification
- ✅ Production-ready layouts
The Livewire starter kit provides a beautiful foundation to build upon, saving hours of boilerplate setup!
Step 4: Create Application Layout
If you didn't use a starter kit, you'll need to create a layout for your Livewire components. Laravel 12 makes this easy with a built-in command.
Generate Default Layout
# Create the default Livewire layout
php artisan livewire:layoutThis creates resources/views/components/layouts/app.blade.php with this structure:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title ?? 'Laravel 12 with Livewire 3' }}</title>
</head>
<body>
{{ $slot }}
</body>
</html>Enhanced Layout with Tailwind CSS
Let's create a more modern layout for 2025 with Tailwind CSS:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ $title ?? 'Laravel 12 App' }}</title>
<!-- Tailwind CSS via CDN (for quick setup) -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Or use Vite for production -->
<!-- @vite(['resources/css/app.css', 'resources/js/app.js']) -->
</head>
<body class="bg-gray-50 antialiased">
<!-- Navigation -->
<nav class="bg-white shadow-lg">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<a href="/" class="text-xl font-bold text-gray-800">
Laravel 12 + Livewire 3
</a>
</div>
<div class="flex items-center space-x-4">
<a href="/" class="text-gray-600 hover:text-gray-900">Home</a>
<a href="/about" class="text-gray-600 hover:text-gray-900">About</a>
</div>
</div>
</div>
</nav>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{{ $slot }}
</main>
<!-- Footer -->
<footer class="bg-gray-800 text-white mt-12">
<div class="max-w-7xl mx-auto px-4 py-6 text-center">
<p>© 2025 Built with Laravel 12 & Livewire 3</p>
</div>
</footer>
</body>
</html>Important: Livewire 3 automatically injects its JavaScript and CSS assets. No need to manually include @livewireStyles or @livewireScripts unless you want manual control!
Step 5: Create Your First Livewire Component in Laravel 12
Now for the exciting part - creating your first reactive Livewire 3 component! Let's build a modern counter with enhanced features for 2025.
Generate the Component
# Create a Counter component
php artisan make:livewire Counter
# Output:
# CLASS: app/Livewire/Counter.php
# VIEW: resources/views/livewire/counter.blade.phpBuild the Component Class
Open app/Livewire/Counter.php and add this code:
<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\Title;
#[Title('Counter - Laravel 12 Demo')]
class Counter extends Component
{
// Public properties are automatically available in the view
public int $count = 0;
public int $step = 1;
// Method to increment counter
public function increment()
{
$this->count += $this->step;
}
// Method to decrement counter
public function decrement()
{
$this->count -= $this->step;
}
// Reset counter to zero
public function reset()
{
$this->count = 0;
}
// Render the component view
public function render()
{
return view('livewire.counter');
}
}Create the Component View
Open resources/views/livewire/counter.blade.php:
<div class="max-w-md mx-auto mt-10">
<div class="bg-white rounded-2xl shadow-xl p-8">
<h2 class="text-3xl font-bold text-center text-gray-800 mb-8">
Livewire 3 Counter
</h2>
<!-- Counter Display -->
<div class="text-center mb-8">
<div class="text-7xl font-bold text-blue-600 mb-4">
{{ $count }}
</div>
<p class="text-gray-500">Current Count</p>
</div>
<!-- Step Size Selector -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">
Step Size: {{ $step }}
</label>
<input
type="range"
wire:model.live="step"
min="1"
max="10"
class="w-full"
>
</div>
<!-- Action Buttons -->
<div class="grid grid-cols-3 gap-4">
<button
wire:click="decrement"
class="bg-red-500 hover:bg-red-600 text-white font-bold py-3 px-6 rounded-lg transition duration-200 transform hover:scale-105">
<span class="text-2xl">−</span>
</button>
<button
wire:click="reset"
class="bg-gray-500 hover:bg-gray-600 text-white font-bold py-3 px-6 rounded-lg transition duration-200">
Reset
</button>
<button
wire:click="increment"
class="bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-6 rounded-lg transition duration-200 transform hover:scale-105">
<span class="text-2xl">+</span>
</button>
</div>
<!-- Loading Indicator -->
<div wire:loading class="mt-4 text-center text-gray-500 text-sm">
Processing...
</div>
</div>
</div>Understanding the Code
wire:click="method"- Calls PHP method when clickedwire:model.live="property"- Two-way binding with real-time updateswire:loading- Shows content during network requests#[Title]- Sets page title (new in Livewire 3)
Step 6: Register Component Routes
Let's register routes to access our Livewire components. Open routes/web.php:
<?php
use Illuminate\Support\Facades\Route;
use App\Livewire\Counter;
// Welcome page
Route::get('/', function () {
return view('welcome');
});
// Full-page Livewire component
Route::get('/counter', Counter::class);Livewire 3 in Laravel 12 supports full-page components - simply pass the component class to the route!
Step 7: Test Your Laravel 12 Livewire Application
Time to see your creation in action! Start the Laravel development server:
# Start the server
php artisan serve
# Visit in your browser:
# http://localhost:8000/counterYou should see your interactive counter! Try these actions:
- ✅ Click the + and − buttons - count updates instantly!
- ✅ Adjust the step slider - see the step size change in real-time
- ✅ Click Reset - counter goes back to zero
- ✅ Watch the loading indicator during updates
Congratulations! 🎉 You've successfully set up Laravel 12 with Livewire 3 and created your first reactive component. All this interactivity with ZERO JavaScript code written!
Building a Real-World Component: Task Manager
Let's create something more practical - a task management component showcasing Livewire 3's powerful features in Laravel 12.
Generate the Component
php artisan make:livewire TaskManagerComponent Class with Validation
<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\Title;
use Livewire\Attributes\Validate;
#[Title('Task Manager - Laravel 12')]
class TaskManager extends Component
{
#[Validate('required|min:3|max:100')]
public string $newTask = '';
public array $tasks = [];
public string $filter = 'all'; // all, completed, active
public function mount()
{
// Initialize with sample tasks
$this->tasks = [
[
'id' => 1,
'title' => 'Setup Laravel 12 with Livewire 3',
'completed' => true,
'created_at' => now()->subHours(2)->format('g:i A')
],
[
'id' => 2,
'title' => 'Build amazing reactive components',
'completed' => false,
'created_at' => now()->subHour()->format('g:i A')
],
];
}
public function addTask()
{
$this->validate();
$this->tasks[] = [
'id' => count($this->tasks) + 1,
'title' => $this->newTask,
'completed' => false,
'created_at' => now()->format('g:i A')
];
$this->newTask = '';
$this->dispatch('task-added'); // Dispatch browser event
}
public function toggleTask($id)
{
$this->tasks = array_map(function($task) use ($id) {
if ($task['id'] === $id) {
$task['completed'] = !$task['completed'];
}
return $task;
}, $this->tasks);
}
public function deleteTask($id)
{
$this->tasks = array_filter(
$this->tasks,
fn($task) => $task['id'] !== $id
);
}
public function getFilteredTasksProperty()
{
return match($this->filter) {
'completed' => array_filter($this->tasks, fn($t) => $t['completed']),
'active' => array_filter($this->tasks, fn($t) => !$t['completed']),
default => $this->tasks
};
}
public function render()
{
return view('livewire.task-manager');
}
}Component View
<div class="max-w-2xl mx-auto mt-10">
<div class="bg-white rounded-2xl shadow-2xl overflow-hidden">
<!-- Header -->
<div class="bg-gradient-to-r from-blue-600 to-purple-600 p-6">
<h1 class="text-3xl font-bold text-white">Task Manager 2025</h1>
<p class="text-blue-100 mt-1">Built with Laravel 12 & Livewire 3</p>
</div>
<div class="p-6">
<!-- Add Task Form -->
<form wire:submit="addTask" class="mb-6">
<div class="flex gap-3">
<div class="flex-1">
<input
type="text"
wire:model="newTask"
wire:keydown.enter="addTask"
placeholder="What needs to be done?"
class="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none transition"
>
@error('newTask')
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
<button
type="submit"
class="bg-blue-600 hover:bg-blue-700 text-white font-semibold px-8 py-3 rounded-lg transition duration-200">
Add Task
</button>
</div>
</form>
<!-- Filter Tabs -->
<div class="flex gap-2 mb-6 border-b">
<button
wire:click="$set('filter', 'all')"
class="px-4 py-2 {{ $filter === 'all' ? 'border-b-2 border-blue-600 text-blue-600' : 'text-gray-600' }}">
All ({{ count($tasks) }})
</button>
<button
wire:click="$set('filter', 'active')"
class="px-4 py-2 {{ $filter === 'active' ? 'border-b-2 border-blue-600 text-blue-600' : 'text-gray-600' }}">
Active
</button>
<button
wire:click="$set('filter', 'completed')"
class="px-4 py-2 {{ $filter === 'completed' ? 'border-b-2 border-blue-600 text-blue-600' : 'text-gray-600' }}">
Completed
</button>
</div>
<!-- Task List -->
<div class="space-y-3">
@forelse($this->filteredTasks as $task)
<div
wire:key="task-{{ $task['id'] }}"
class="flex items-center gap-4 p-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition">
<!-- Checkbox -->
<input
type="checkbox"
wire:click="toggleTask({{ $task['id'] }})"
{{ $task['completed'] ? 'checked' : '' }}
class="w-5 h-5 text-blue-600 rounded cursor-pointer"
>
<!-- Task Content -->
<div class="flex-1">
<p class="{{ $task['completed'] ? 'line-through text-gray-400' : 'text-gray-800' }}">
{{ $task['title'] }}
</p>
<p class="text-xs text-gray-500 mt-1">
Added at {{ $task['created_at'] }}
</p>
</div>
<!-- Delete Button -->
<button
wire:click="deleteTask({{ $task['id'] }})"
wire:confirm="Are you sure you want to delete this task?"
class="text-red-500 hover:text-red-700 font-medium">
Delete
</button>
</div>
@empty
<div class="text-center py-12 text-gray-400">
<p class="text-lg">No tasks found</p>
<p class="text-sm">Add your first task above!</p>
</div>
@endforelse
</div>
<!-- Loading Overlay -->
<div wire:loading class="fixed inset-0 bg-black bg-opacity-10 flex items-center justify-center">
<div class="bg-white rounded-lg p-4 shadow-lg">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div>
<p class="mt-2 text-sm text-gray-600">Loading...</p>
</div>
</div>
</div>
</div>
<!-- Toast Notification -->
<div
x-data="{ show: false }"
@task-added.window="show = true; setTimeout(() => show = false, 3000)"
x-show="show"
x-transition
class="fixed bottom-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg">
✓ Task added successfully!
</div>
</div>Add the Route
Route::get('/tasks', \App\Livewire\TaskManager::class);Visit http://localhost:8000/tasks to see your task manager in action!
Livewire 3 Features You Should Know
1. Reactive Properties with wire:model.live
<!-- Real-time updates as user types -->
<input type="text" wire:model.live="search">
<!-- Update on blur (when field loses focus) -->
<input type="text" wire:model.blur="email">
<!-- Debounced updates (wait 500ms after typing stops) -->
<input type="text" wire:model.live.debounce.500ms="query">2. Form Validation with Attributes
use Livewire\Attributes\Validate;
#[Validate('required|email|unique:users')]
public string $email = '';
#[Validate('required|min:8')]
public string $password = '';
public function save()
{
$this->validate(); // Validates all properties with #[Validate]
// Save logic here
}3. Loading States
<!-- Show during any Livewire update -->
<div wire:loading>Processing...</div>
<!-- Show during specific action -->
<div wire:loading wire:target="save">Saving...</div>
<!-- Hide element during loading -->
<button wire:loading.remove>Submit</button>
<!-- Disable element during loading -->
<button wire:loading.attr="disabled">Submit</button>4. Events and Communication
// Dispatch event from component
$this->dispatch('user-created', userId: $user->id);
// Listen for event
use Livewire\Attributes\On;
#[On('user-created')]
public function handleUserCreated($userId)
{
// Handle the event
}5. Computed Properties
use Livewire\Attributes\Computed;
#[Computed]
public function totalPrice()
{
return $this->items->sum('price');
}
// Access in view: {{ $this->totalPrice }}Laravel 12 & Livewire 3 Best Practices for 2025
1. Optimize Network Requests
Use wire:model.live.debounce for search inputs to reduce server load:
<!-- Bad: Sends request on every keystroke -->
<input wire:model.live="search">
<!-- Good: Waits 300ms after user stops typing -->
<input wire:model.live.debounce.300ms="search">2. Use Lazy Loading for Better Performance
use Livewire\Attributes\Lazy;
#[Lazy]
class ExpensiveComponent extends Component
{
public function render()
{
// This won't run until component becomes visible
$data = $this->fetchExpensiveData();
return view('livewire.expensive-component', compact('data'));
}
}3. Leverage Alpine.js for Client-Side Logic
Alpine.js is bundled with Livewire 3 in Laravel 12. Use it for simple interactions:
<div x-data="{ open: false }">
<button @click="open = !open">Toggle</button>
<div x-show="open" x-transition>
Content that appears/disappears instantly (no server request!)
</div>
</div>4. Use Computed Properties for Expensive Operations
// Cached result - only recomputes when dependencies change
#[Computed]
public function filteredPosts()
{
return Post::where('status', 'published')
->with('author', 'comments')
->latest()
->get();
}5. Validate User Input Properly
use Livewire\Attributes\Validate;
class ContactForm extends Component
{
#[Validate('required|min:3')]
public string $name = '';
#[Validate('required|email')]
public string $email = '';
#[Validate('required|min:10')]
public string $message = '';
public function submit()
{
$validated = $this->validate();
// Process the validated data
Contact::create($validated);
session()->flash('success', 'Message sent!');
}
}Advanced Configuration for Laravel 12
Publish Configuration File
# Publish Livewire config (optional)
php artisan livewire:publish --configThis creates config/livewire.php where you can customize:
<?php
return [
// Automatically inject assets (default: true)
'inject_assets' => true,
// Asset URL configuration
'asset_url' => null,
// Middleware for Livewire routes
'middleware_group' => 'web',
// Temporary file uploads
'temporary_file_upload' => [
'disk' => null,
'rules' => null,
'directory' => null,
],
// Pagination theme
'pagination_theme' => 'tailwind',
];Manual Asset Control
If you want manual control over Livewire assets:
<!DOCTYPE html>
<html>
<head>
@livewireStyles
</head>
<body>
{{ $slot }}
@livewireScripts
</body>
</html>Troubleshooting Common Issues
Issue 1: Livewire Assets Not Loading
Solution:
# Clear all caches
php artisan cache:clear
php artisan config:clear
php artisan view:clear
php artisan route:clear
# Restart development server
php artisan serveIssue 2: Components Not Updating
Checklist:
- ✓ Ensure component has single root element
- ✓ Check public properties are correctly defined
- ✓ Verify method names match wire:click attributes
- ✓ Look for JavaScript errors in browser console
Issue 3: Alpine.js Conflicts
Solution: Remove any separate Alpine.js installations - it's bundled with Livewire 3:
# Check package.json and remove Alpine if present
# Remove from resources/js/app.js if importedEmbedding Livewire Components in Blade Views
You can embed Livewire components anywhere in your Blade templates:
Method 1: Component Tag
<!-- Simple embedding -->
<livewire:counter />
<!-- Pass data to component -->
<livewire:counter :count="10" :step="2" />
<!-- Nested in other Blade content -->
<div class="container">
<h1>Welcome to My App</h1>
<livewire:task-manager />
</div>Method 2: Blade Directive
<!-- Simple -->
@livewire('counter')
<!-- With parameters -->
@livewire('counter', ['count' => 10, 'step' => 2])
<!-- With named slots -->
@livewire('card-component', ['title' => 'My Card'])Next Steps: Mastering Livewire 3
You've successfully set up Laravel 12 with Livewire 3! Here's what to explore next:
Advanced Features to Learn:
- File Uploads: Handle file uploads with progress bars and preview
- Real-Time Features: Integrate Laravel Echo for WebSocket support
- Pagination: Build paginated lists with Livewire pagination
- Form Objects: Use form objects for complex form handling
- Nested Components: Build complex UIs with component composition
- Testing: Write feature tests for your Livewire components
- Security: Implement authorization and CSRF protection
- Performance: Optimize with lazy loading and computed properties
Recommended Learning Resources:
- 📚 Official Livewire Documentation
- 🎓 Laracasts Livewire 3 Course
- 💡 Laravel News for Latest Updates
- 🎥 YouTube Livewire Tutorials
Conclusion
Congratulations on completing this comprehensive guide to setting up Laravel 12 with Livewire 3 ! You've learned how to install Laravel 12, integrate Livewire 3, create reactive components, and implement best practices for modern web development.
Laravel 12's zero-breaking-changes approach combined with Livewire 3's powerful reactive features makes this the perfect time to build dynamic applications without JavaScript complexity. With official starter kits, enhanced Alpine.js integration, and improved performance, you're equipped with the best tools Laravel has to offer.
Remember, Livewire 3 in Laravel 12 gives you the power to build SPA-like experiences using only PHP and Blade. No API layers, no complex JavaScript frameworks - just clean, maintainable Laravel code that feels modern and responsive.
Start building your next project with Laravel 12 and Livewire 3 today, and experience the joy of full-stack PHP development !
Useful Resources for 2025
- Laravel 12 Official Documentation
- Livewire 3 Documentation
- Livewire GitHub Repository
- Alpine.js Documentation
- Tailwind CSS Documentation
- Flux UI Components
Frequently Asked Questions
Related Articles You May Like
- Top Coding Tips: Clean Code, Boost Productivity, Master Practices
Best Practices • Intermediate
- The Ultimate Guide to Code Debugging: Techniques, Tools & Tips
Debugging • Intermediate
- Laravel API Example: Creating Efficient Endpoints
Laravel • Advanced
- Laravel Tips and Tricks: Hidden Features Most Developers Miss
Laravel • Advanced
- How to Debug Laravel SQL Queries in API Requests: A Developer's Guide
Laravel • Intermediate
- Setting Up Gmail SMTP in Laravel: A Comprehensive Guide
Laravel • Intermediate