CRUD stands for Create, Read, Update, Delete — the four basic operations found in almost every web application. In Laravel, building CRUD can be done very efficiently thanks to features like the Eloquent ORM, Resource Controllers, and Blade templating. This article will guide you through building complete CRUD from scratch using Laravel 10/11.
Initial Setup
Make sure you have installed Laravel and set up a database. Create a new project if you don't have one yet:
composer create-project laravel/laravel crud-demo
cd crud-demo
cp .env.example .env
php artisan key:generate
Configure the database connection in the .env file:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=crud_demo
DB_USERNAME=root
DB_PASSWORD=
Creating the Migration and Model
We will build a CRUD feature for product data. Run the following command to create the model and its migration at once:
php artisan make:model Product -m
Open the newly created migration file in the database/migrations/ folder and add the columns you need:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->decimal('price', 10, 2);
$table->integer('stock')->default(0);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('products');
}
};
Run the migration:
php artisan migrate
Filling in the Product Model
Open app/Models/Product.php and add the $fillable property:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = ['name', 'description', 'price', 'stock'];
}
Creating a Resource Controller
A resource controller automatically provides methods for all CRUD operations:
php artisan make:controller ProductController --resource --model=Product
Open app/Http/Controllers/ProductController.php and fill in each method:
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function index()
{
$products = Product::latest()->paginate(10);
return view('products.index', compact('products'));
}
public function create()
{
return view('products.create');
}
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
'stock' => 'required|integer|min:0',
]);
Product::create($request->all());
return redirect()->route('products.index')
->with('success', 'Product added successfully.');
}
public function show(Product $product)
{
return view('products.show', compact('product'));
}
public function edit(Product $product)
{
return view('products.edit', compact('product'));
}
public function update(Request $request, Product $product)
{
$request->validate([
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
'stock' => 'required|integer|min:0',
]);
$product->update($request->all());
return redirect()->route('products.index')
->with('success', 'Product updated successfully.');
}
public function destroy(Product $product)
{
$product->delete();
return redirect()->route('products.index')
->with('success', 'Product deleted successfully.');
}
}
Registering the Route
Open routes/web.php and register the resource route:
use App\Http\Controllers\ProductController;
Route::resource('products', ProductController::class);
This single line automatically registers 7 routes: index, create, store, show, edit, update, and destroy.
Creating the Blade View
Create the resources/views/products/ folder, then create an index.blade.php file:
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Product List</h1>
<a href="{{ route('products.create') }}" class="btn btn-primary">Add Product</a>
@if(session('success'))
<div class="alert alert-success mt-2">{{ session('success') }}</div>
@endif
<table class="table mt-3">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Stock</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach($products as $product)
<tr>
<td>{{ $product->name }}</td>
<td>$ {{ number_format($product->price, 2) }}</td>
<td>{{ $product->stock }}</td>
<td>
<a href="{{ route('products.edit', $product) }}" class="btn btn-sm btn-warning">Edit</a>
<form action="{{ route('products.destroy', $product) }}" method="POST" style="display:inline">
@csrf
@method('DELETE')
<button class="btn btn-sm btn-danger">Delete</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
{{ $products->links() }}
</div>
@endsection
Running the Application
After all the views are created (create.blade.php and edit.blade.php with the appropriate forms), start the server:
php artisan serve
Visit http://localhost:8000/products to see the result.
Conclusion
You have successfully built a complete CRUD feature in Laravel using a Resource Controller and the Eloquent ORM. With this approach, your code is structured and easy to extend. As a next step, you can add more complex validation, image uploads, or wrap this CRUD with authentication using Laravel Breeze.