Laravel Livewire CRUD Tutorial: Step-by-Step Guide for Beginners

Introduction to Laravel Livewire CRUD Applications
Modern web development often revolves around creating interfaces that are dynamic, responsive, and easy to maintain. Laravel Livewire is a powerful tool that brings reactive UI development to Laravel, making it possible to build complex, dynamic interfaces directly in PHP without writing a line of JavaScript. In this Laravel Livewire CRUD tutorial, you'll learn how to harness Livewire to implement full-featured CRUD (Create, Read, Update, Delete) operations in your Laravel applications.
CRUD operations are the backbone of nearly every web application, whether you're building a blog, an e-commerce store, or an admin dashboard. Livewire revolutionizes the way we approach these operations by enabling real-time user experiences—think instant form updates, error feedback, and smooth pagination—all with server-rendered components and minimal JavaScript.
By the end of this multi-part guide, you'll understand how to set up a CRUD application from scratch using Laravel and Livewire, leveraging features like real-time validation, data binding, and component-based design. You'll see why Livewire is especially appealing for Laravel beginners and seasoned developers alike who want to create rich, interactive applications without leaving the comfort of PHP.
What You'll Learn
- What is Laravel Livewire? Gain a foundational understanding of Livewire and how it integrates with Laravel.
- Benefits of Livewire for CRUD Operations: See what makes Livewire unique for building CRUD interfaces—fast prototyping, no JavaScript hassle, and seamless data binding.
- Key CRUD Features: Identify the core features of a CRUD app (forms, validation, data listing, editing, deleting) and how Livewire addresses them.
- Tutorial Roadmap: Get a clear picture of what you’ll build—an interactive CRUD application with Livewire, step by step.
If you’re comfortable with basic Laravel concepts and eager to enhance your development workflow, this Livewire CRUD example will give you a robust, practical foundation. In the next sections, we’ll guide you through environment setup, Livewire installation, component creation, data binding, and more.
Further Reading
- Laravel Livewire Documentation — Provides the official introduction and overview of Livewire.
- Laravel Official Documentation — Essential for understanding Laravel’s core concepts.
Setting Up Your Laravel Development Environment
Before diving into Livewire CRUD operations, you need a solid Laravel development environment. This ensures a smooth workflow as you build and test your application.
Step 1: Install Composer
Composer is the dependency manager Laravel relies on. If you haven’t installed Composer:
- Visit getcomposer.org/download and follow the instructions for your operating system.
- Verify installation by running:
You should see the installed Composer version.composer --version
Step 2: Install Laravel
While you can install Laravel globally, many developers prefer the Composer create-project approach for each app:
-
In your terminal, run:
composer create-project laravel/laravel livewire-crud-demoReplace
livewire-crud-demowith your preferred directory name. -
Move into your new project directory:
cd livewire-crud-demo
Step 3: Configure the Local Database
- Install a local database server (MySQL, MariaDB, or SQLite).
- Create a new database for your project—e.g.,
livewire_crud. - Open your project’s
.envfile and update the following lines:
Adjust the values for your local setup.DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=livewire_crud DB_USERNAME=root DB_PASSWORD=your_password
Step 4: Verify Your Environment
To confirm your Laravel app is running:
- Start the built-in server:
php artisan serve - Visit
http://localhost:8000in your browser. You should see the Laravel welcome page.
Checklist before moving on:
- Composer is installed and working
- New Laravel project created
- Database created and connected
- Laravel app runs locally
You’re now ready to install Livewire and start building your CRUD application!
Further Reading
- Composer Documentation — Essential for managing Laravel and PHP dependencies.
- Laravel Installation Guide — Step-by-step Laravel installation instructions.
Installing and Configuring Livewire in Laravel
With your Laravel project set up, it’s time to install Livewire and prepare your environment for interactive development. Livewire integrates seamlessly with Laravel, enabling fast prototyping and dynamic interfaces.
Step 1: Install Livewire via Composer
From your project root, run:
composer require livewire/livewire
This command downloads and registers Livewire as a dependency in your Laravel app.
Step 2: Publish Livewire Assets
Most modern Laravel frontends use Blade templates. Livewire works out-of-the-box, but you must add its assets (JavaScript and CSS) to your main layout. In your resources/views/layouts/app.blade.php (or equivalent), add this before the closing </body> tag:
@livewireScripts
And inside the <head> tag, add:
@livewireStyles
If you’re using Laravel Breeze, Jetstream, or another starter kit, check where your main layout is located.
Step 3: Understand Livewire Directory Structure
When you create a Livewire component, two files are generated:
- A PHP class (e.g.,
app/Http/Livewire/ExampleComponent.php) - A Blade view (e.g.,
resources/views/livewire/example-component.blade.php)
This structure makes it easy to separate logic and presentation, following Laravel’s conventions.
Step 4: Test Livewire with a Sample Component
Let’s make sure everything works by creating a simple Livewire component:
- Generate a component called
HelloWorld:php artisan make:livewire HelloWorld - This creates:
app/Http/Livewire/HelloWorld.phpresources/views/livewire/hello-world.blade.php
- Edit the Blade view to display a message:
<!-- resources/views/livewire/hello-world.blade.php --> <div> <h3>Hello from Livewire!</h3> </div> - In a Blade page (e.g.,
resources/views/welcome.blade.php), render the component:<livewire:hello-world /> - Reload the page. If you see “Hello from Livewire!”—congratulations, Livewire is set up!
Further Reading
- Livewire Installation Docs — Covers installation and setup in detail.
Understanding Livewire Components and Data Binding
Livewire’s core power lies in its components and automatic data binding. Components encapsulate UI and logic, updating instantly as users interact—without writing JavaScript.
Creating a Basic Livewire Component
Let’s create a simple counter to demonstrate Livewire’s magic:
- Generate a component:
php artisan make:livewire Counter - Open the component class (
app/Http/Livewire/Counter.php):<?php namespace App\Http\Livewire; use Livewire\Component;class Counter extends Component { public $count = 0;
public function increment() { $this->count++; } public function render() { return view('livewire.counter'); }} - Edit the Blade view (
resources/views/livewire/counter.blade.php):<div> <h4>Count: {{ $count }}</h4> <button wire:click="increment">+</button> </div> - Add
<livewire:counter />to any Blade file and refresh your browser. Clicking “+” updates the count—no JavaScript needed!
Understanding Component Lifecycle
Livewire components are stateful. Each time a user interacts (clicks a button, types in a field), Livewire automatically syncs state between the browser and server, re-rendering only what’s changed.
- Mounting: When the component is loaded, its public properties are initialized.
- Updating: When an action is triggered (e.g., a button click), Livewire runs the corresponding method and re-renders the view.
- Destroying: When the component is removed from the DOM, its state is cleared.
Two-Way Data Binding
Livewire’s real-time data binding lets you sync data between frontend and backend instantly. Here’s an example with a text input:
<div>
<input type="text" wire:model="count">
<span>The count is: {{ $count }}</span>
</div>
- Typing in the input updates the
$countproperty in the backend immediately. - Changes made in PHP are reflected in the input field automatically.
Seeing Data Binding in Action
Try editing the Counter component to accept user input:
public $count = 0;
<div>
<input type="number" wire:model="count">
<button wire:click="increment">Increase</button>
<div>Current value: {{ $count }}</div>
</div>
Now, changing the input or clicking the button both update $count.
Further Reading
- Livewire Data Binding — Deep dive into how Livewire syncs data.
Designing the Database and Building the Model
A CRUD application is only as good as its data layer. Let’s design a simple database schema, create migrations, and build an Eloquent model—all perfectly suited for Livewire integration.
Step 1: Plan the Database Schema
For this tutorial, we’ll manage a list of posts. Each post will have:
id(primary key)title(string)content(text)created_atandupdated_at(timestamps)
Step 2: Create the Migration
- In your terminal, run:
This creates a model and a migration file.php artisan make:model Post -m - Edit the migration file in
database/migrations/(it will look likexxxx_xx_xx_create_posts_table.php):public function up() { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('content'); $table->timestamps(); }); }
Step 3: Run the Migration
Apply your migration to create the table:
php artisan migrate
If you see a success message, your posts table is ready.
Step 4: Build the Eloquent Model
Open app/Models/Post.php and ensure it looks like this:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model;
class Post extends Model { use HasFactory; protected $fillable = ['title', 'content']; }
$fillable lets you safely mass-assign title and content—essential for Livewire forms.
Step 5: Verify the Setup
You can quickly test by opening Laravel Tinker:
php artisan tinker
Then run:
\App\Models\Post::create(['title' => 'Hello World', 'content' => 'This is my first post.']);
Check your database—your post should be there!
You now have a solid database and model foundation for CRUD with Livewire. In the next part, you’ll start building interactive forms, listing posts, and implementing full CRUD features.
Further Reading
- Laravel Migrations — Official guide to creating and running migrations.
- Laravel Eloquent ORM — Explains working with models and database records.
Creating Livewire CRUD Components
In Part 1, you prepared your Laravel project, installed Livewire, and set up your Eloquent model for the data you want to manage. Now, we’ll build out the core of your Laravel Livewire CRUD application: the Livewire components that power listing, creating, editing, and deleting records—all in real-time, without page reloads.
Livewire lets you encapsulate UI and logic inside components that respond instantly to user actions. You’ll see how Livewire’s data binding and event system make Laravel CRUD operations fluid and interactive.
1. Generating CRUD Components
Let’s create a Livewire component for managing a simple resource (for example, Post). This pattern works for any Eloquent model.
Generate a Livewire component:
php artisan make:livewire PostCrud
This command creates two files:
app/Http/Livewire/PostCrud.php(the PHP component class)resources/views/livewire/post-crud.blade.php(the Blade view)
2. Displaying Records (Read)
First, let’s list all posts in our Livewire component. Open PostCrud.php and set up a property for your records:
// app/Http/Livewire/PostCrud.php namespace App\Http\Livewire;use Livewire\Component; use App\Models\Post;
class PostCrud extends Component { public $posts;
public function render() { $this->posts = Post::orderBy('created_at', 'desc')->get(); return view('livewire.post-crud'); }
}
Now, in post-crud.blade.php, display the posts:
<!-- resources/views/livewire/post-crud.blade.php -->
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach ($posts as $post)
<tr>
<td>{{ $post->title }}</td>
<td>
<button wire:click="edit({{ $post->id }})">Edit</button>
<button wire:click="delete({{ $post->id }})">Delete</button>
</td>
</tr>
@endforeach
</tbody>
</table>
3. Adding Create, Edit, and Delete Actions
Creating Records
Add properties for form inputs and a method to handle creation:
public $title;
public function create() { Post::create(['title' => $this->title]); $this->reset('title'); // Clear input after creation }
In your Blade view, add a simple form:
<form wire:submit.prevent="create">
<input type="text" wire:model="title" placeholder="Post title">
<button type="submit">Add Post</button>
</form>
Editing Records
Add properties and methods for editing:
public $postId;public function edit($id) { $post = Post::findOrFail($id); $this->postId = $post->id; $this->title = $post->title; }
public function update() { $post = Post::findOrFail($this->postId); $post->update(['title' => $this->title]); $this->reset(['postId', 'title']); }
Toggle between create/update in your view:
<form wire:submit.prevent="{{ $postId ? 'update' : 'create' }}">
<input type="text" wire:model="title" placeholder="Post title">
<button type="submit">
{{ $postId ? 'Update Post' : 'Add Post' }}
</button>
@if($postId)
<button type="button" wire:click="$set('postId', null)">Cancel</button>
@endif
</form>
Deleting Records
Add a delete method:
public function delete($id)
{
Post::findOrFail($id)->delete();
}
Livewire’s Event System
Livewire makes it easy to communicate between components or trigger browser events. For example, you can emit messages after CRUD actions:
public function create()
{
Post::create(['title' => $this->title]);
$this->reset('title');
$this->emit('postCreated');
}
Listen for these events in JavaScript or other Livewire components for advanced UI updates.
4. Micro-Project: Full CRUD with Livewire
Try wiring up create, edit, and delete for your own Eloquent model (e.g. Category, Product). Use the same steps above. This hands-on approach will reinforce how Livewire CRUD logic fits together.
Further Reading
- Livewire CRUD Example (Official Docs) — A practical guide to CRUD with Livewire.
Building Interactive Forms with Livewire
Livewire truly shines when handling forms. Its real-time data binding and validation make creating dynamic, responsive forms straightforward—perfect for modern CRUD applications. In this section, you'll learn how to build interactive Laravel Livewire forms, including dynamic fields and file uploads, while keeping user experience high.
1. Building a Responsive Livewire Form
You already saw a basic form in the previous section. Let’s enhance it for a more realistic Livewire CRUD example.
Example: Post with Title, Content, and Image
Update your Livewire component:
public $title, $content, $image;
Update the Blade view:
<form wire:submit.prevent="{{ $postId ? 'update' : 'create' }}">
<input type="text" wire:model="title" placeholder="Title">
<textarea wire:model="content" placeholder="Content"></textarea>
<input type="file" wire:model="image">
<button type="submit">{{ $postId ? 'Update' : 'Create' }}</button>
</form>
Livewire automatically binds form inputs to your component’s public properties. Any change in the input instantly updates the property.
2. Implementing Dynamic Form Fields
Suppose you want to let users add multiple tags to a post. You can use arrays and Livewire’s dynamic features:
Add to your component:
public $tags = [''];public function addTag() { $this->tags[] = ''; }
public function removeTag($index) { unset($this->tags[$index]); $this->tags = array_values($this->tags); // Reindex }
Update your Blade view:
@foreach($tags as $index => $tag)
<input type="text" wire:model="tags.{{ $index }}" placeholder="Tag">
<button type="button" wire:click="removeTag({{ $index }})">Remove</button>
@endforeach
<button type="button" wire:click="addTag">Add Tag</button>
This gives users the power to add or remove tag fields on the fly.
3. Handling File Uploads
Livewire supports file uploads with minimal setup.
Add the WithFileUploads trait to your component:
use Livewire\WithFileUploads;
class PostCrud extends Component { use WithFileUploads; // ... }
Handle uploads in your create/update methods:
public function create()
{
$imagePath = $this->image->store('images', 'public');
Post::create([
'title' => $this->title,
'content' => $this->content,
'image_path' => $imagePath,
]);
$this->reset(['title', 'content', 'image']);
}
4. Enhancing UX with Real-Time Feedback
Livewire’s power is in instant updates. Here’s how to boost UX:
-
Show a preview while uploading images:
@if ($image) <img src="{{ $image->temporaryUrl() }}" width="120"> @endif -
Display loading indicators:
<div wire:loading>Uploading...</div> -
Use validation feedback (covered next section).
Tips for Great Livewire Forms
- Keep stateful properties ($title, $content, etc.) public.
- Use wire:model for two-way binding.
- Use wire:loading and wire:target for granular loading states.
- Reset fields after submission.
Further Reading
- Livewire File Uploads (Official Docs) — Details on handling file uploads in Livewire forms.
Validating Data in Livewire CRUD Operations
Data validation is essential for any CRUD application. Livewire brings Laravel’s powerful validation engine to your component classes, allowing you to validate user input in real time and provide instant feedback.
1. Applying Validation Rules in Livewire
Use the validate() method in your create/update actions:
public function create() { $validated = $this->validate([ 'title' => 'required|min:3', 'content' => 'required', 'image' => 'nullable|image|max:1024', ]);// Save using $validated array Post::create([ 'title' => $validated['title'], 'content' => $validated['content'], 'image_path' => $this->image ? $this->image->store('images', 'public') : null, ]); $this->reset(['title', 'content', 'image']);
}
For inline validation on the fly, use updated() hooks:
public function updated($propertyName)
{
$this->validateOnly($propertyName, [
'title' => 'required|min:3',
'content' => 'required',
'image' => 'nullable|image|max:1024',
]);
}
2. Showing Validation Errors in Forms
Livewire automatically populates an $errors variable in your Blade views:
<input type="text" wire:model="title">
@error('title') <span class="text-danger">{{ $message }}</span> @enderror
Show global errors as a list:
@if ($errors->any())
<ul>
@foreach ($errors->all() as $error)
<li class="text-danger">{{ $error }}</li>
@endforeach
</ul>
@endif
3. Custom Validation Messages
Customize messages by passing a third argument to validate():
$this->validate([
'title' => 'required|min:3',
], [
'title.required' => 'Please enter a title.',
'title.min' => 'The title must be at least 3 characters.',
]);
4. Livewire’s Validation Lifecycle
- On submit:
validate()runs all rules. - On input change:
validateOnly()runs for that field. - On error: Errors show instantly in your UI.
- On success: Errors clear automatically when valid.
Micro-Project: Add Validation to Your CRUD
- Add validation rules for each field.
- Try a custom error message for required fields.
- Experiment with
validateOnly()to see instant error feedback as you type.
Further Reading
- Laravel Validation (Official Docs) — Covers all of Laravel's validation capabilities.
- Livewire Validation (Official Docs) — Explains validation in Livewire components.
Enhancing UX with Modals and Real-Time Updates
Modern users expect seamless, responsive interfaces. Modals let users create, edit, or confirm deletion of records without navigating away or reloading the page. Combined with Livewire’s real-time updates, you’ll deliver a polished CRUD application that feels snappy and modern.
1. Adding Modal Dialogs
Let’s use Bootstrap modals (or your preferred UI framework) in your Blade view. Here’s a basic edit modal example:
<!-- Edit Modal -->
<div class="modal fade" id="editModal" tabindex="-1" aria-hidden="true" wire:ignore.self>
<div class="modal-dialog">
<div class="modal-content">
<form wire:submit.prevent="update">
<div class="modal-header">
<h5 class="modal-title">Edit Post</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="text" wire:model="title">
<textarea wire:model="content"></textarea>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</form>
</div>
</div>
</div>
2. Wiring Modal Interactions with Livewire Events
When the user clicks "Edit" on a post, you want to show the modal and load the data. Use Livewire’s event system:
In your component:
public function edit($id)
{
$post = Post::findOrFail($id);
$this->postId = $post->id;
$this->title = $post->title;
$this->content = $post->content;
$this->dispatchBrowserEvent('show-edit-modal');
}
In your Blade view (JavaScript):
<script>
window.addEventListener('show-edit-modal', event => {
var editModal = new bootstrap.Modal(document.getElementById('editModal'));
editModal.show();
});
</script>
3. Real-Time UI Updates
After a successful update or deletion, you can hide the modal and display a notification:
public function update()
{
// ... update logic ...
$this->dispatchBrowserEvent('hide-edit-modal');
session()->flash('message', 'Post updated!');
}
In Blade:
<script> window.addEventListener('hide-edit-modal', event => { var editModal = bootstrap.Modal.getInstance(document.getElementById('editModal')); editModal.hide(); }); </script>
@if (session()->has('message')) <div class="alert alert-success"> {{ session('message') }} </div> @endif
4. Improving User Feedback
- Show spinners during save/delete with
wire:loading. - Use modal confirmations for destructive actions (like delete).
- Add toast or alert messages for success/error.
Micro-Project: Add Edit and Delete Modals
- Implement a delete confirmation modal that appears before deleting a record.
- Show a success message when a record is created, updated, or deleted.
Further Reading
- Livewire Modals Example — Demonstrates using modals in Livewire apps.
- Bootstrap Modals — Reference for styling and using Bootstrap modals.
Implementing Pagination and Searching in Livewire
As your data grows, you’ll want to paginate results and let users search or filter your records. Laravel Livewire makes this a breeze—no JavaScript required.
1. Paginating Eloquent Results
First, install the Livewire pagination trait:
use Livewire\WithPagination;
class PostCrud extends Component { use WithPagination; // ... }
Update your render() method:
public $search = '';
public function render() { $posts = Post::where('title', 'like', '%'.$this->search.'%') ->orderBy('created_at', 'desc') ->paginate(10); return view('livewire.post-crud', compact('posts')); }
In Blade:
<input type="text" wire:model.debounce.500ms="search" placeholder="Search posts..."><table> ... </table>
{{ $posts->links() }}
Livewire will automatically update the table as you paginate or search.
2. Adding Real-Time Searching and Filtering
- Use
wire:modelon your search input for instant updates. - Add filters (e.g., by category) using dropdowns bound to Livewire properties.
- Livewire will re-query and update the table as users type or select filters.
3. Handling Pagination State
Livewire keeps track of the current page in the URL query string. If you want to reset to page 1 when searching, add:
public function updatingSearch()
{
$this->resetPage();
}
4. Optimizing Queries
- Use Eloquent
select()to limit columns if you have large tables. - Eager load relationships with
with()for related data. - Add database indexes on searched columns for speed.
Micro-Project: Pagination and Search
- Add a search bar to your CRUD list.
- Try paginating with different per-page values.
- Add a filter by another field (e.g. category).
Further Reading
- Livewire Pagination (Official Docs) — Official guide for implementing pagination in Livewire.
Testing and Debugging Your Livewire CRUD Application
Building your Livewire CRUD app is just the beginning. Ensuring it works as intended—especially as your codebase grows—means adopting good testing and debugging habits. Laravel and Livewire provide robust tools for both.
1. Writing Tests for Livewire Components
Laravel comes with PHPUnit out-of-the-box. Livewire adds custom testing helpers for your components.
Example: Testing Create Action
use Livewire\Livewire; use App\Models\Post;public function test_can_create_post() { Livewire::test('post-crud') ->set('title', 'Test Post') ->call('create');
$this->assertTrue(Post::where('title', 'Test Post')->exists());
}
- Use
set()to simulate user input. - Use
call()to trigger component methods. - Make assertions on the database or UI.
2. Using Laravel’s Testing Tools
- Run
php artisan testto execute all tests. - Use factories to quickly generate test data.
- Test API endpoints and database state.
3. Debugging Common Livewire Issues
- Use
dd()ordump()in component methods to inspect variables. - Check browser dev tools for network errors or failed AJAX requests.
- Watch for mismatched property names between your Blade view and component.
- Use
php artisan livewire:discoverto troubleshoot component registration.
4. Leveraging Browser Dev Tools and Livewire Logs
- Open your browser’s network tab to inspect Livewire AJAX requests.
- Use the Livewire debug bar (if installed) for performance and event insight.
- Watch for specific error messages in your browser console and Laravel log (
storage/logs/laravel.log).
Micro-Project: Write a Livewire Test
- Test that creating a post works, and that validation errors show when fields are empty.
- Try triggering a delete action and assert the record is gone.
Further Reading
- Laravel Testing (Official Docs) — Feature and unit testing in Laravel.
- Livewire Testing (Official Docs) — How to test Livewire components.
Conclusion and Next Steps
Congratulations! You’ve now built a fully functional Laravel Livewire CRUD application. You’ve learned how to:
- Generate Livewire CRUD components for listing, creating, editing, and deleting records
- Build interactive, real-time forms with validation and file uploads
- Enhance user experience with modals and instant feedback
- Implement pagination and search for scalable data management
- Test and debug your CRUD application for reliability
Your journey with Livewire and Laravel CRUD operations doesn’t stop here. You can continue to refine your application by:
- Adding authorization and user roles
- Implementing advanced search and filtering
- Integrating third-party UI frameworks (like Tailwind or Alpine.js)
- Exploring Livewire’s advanced features: nested components, polling, and more
Where to Go Next?
- Explore the Livewire Community to ask questions and learn from other developers.
- Stay updated with Laravel News for new features and best practices.
- Try building a more complex Livewire CRUD application—think multiple models, relationships, or dashboards.
Keep experimenting, and remember: mastering Livewire CRUD is a stepping stone to building robust, interactive Laravel apps without writing custom JavaScript.
About Prateeksha Web Design
Prateeksha Web Design helps businesses turn tutorials like "Laravel Livewire CRUD Tutorial: Step-by-Step Guide for Beginners" into real-world results with custom websites, performance optimization, and automation. From strategy to implementation, our team supports you at every stage of your digital journey.
Chat with us now Contact us today.