How to Build a Laravel 11 CRUD from Scratch for Beginners

CRUD (Create, Read, Update, Delete) is the foundation of almost every web application. Once you master it in Laravel, building any feature — from a point-of-sale app to an inventor...

How to Build a Laravel 11 CRUD from Scratch for Beginners

CRUD (Create, Read, Update, Delete) is the foundation of almost every web application. Once you master it in Laravel, building any feature — from a point-of-sale app to an inventory system — becomes far easier because the pattern repeats. This tutorial builds a complete product CRUD in Laravel 11 from scratch, with code you can copy and understand.

1. Prepare the Table with a Migration

Instead of creating the table by hand in phpMyAdmin, use a migration so the database structure is tracked in code. Create the model and its migration together:

php artisan make:model Product -m

Open the migration in database/migrations/ and define the columns:

public function up(): void
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->integer('price');
        $table->integer('stock')->default(0);
        $table->text('description')->nullable();
        $table->timestamps();
    });
}
php artisan migrate

2. Set Up the Model

To mass-assign data via create() and update(), list the fillable columns in the $fillable property. This protects you from mass-assignment vulnerabilities:

class Product extends Model
{
    protected $fillable = ['name', 'price', 'stock', 'description'];
}

3. Create a Resource Controller

Laravel has a controller type that scaffolds all seven CRUD methods at once. Create it with the --resource flag:

php artisan make:controller ProductController --resource

Register a single route that maps all of them in routes/web.php:

use App\Http\Controllers\ProductController;

Route::resource('products', ProductController::class);

Run php artisan route:list to see the index, create, store, edit, update, and destroy routes created automatically.

4. Display and Store Data

public function index()
{
    $products = Product::latest()->paginate(10);
    return view('products.index', compact('products'));
}

public function store(StoreProductRequest $request)
{
    Product::create($request->validated());
    return redirect()->route('products.index')
        ->with('success', 'Product created.');
}

5. Clean Validation with Form Requests

Note the StoreProductRequest parameter above. Rather than piling validation rules in the controller, move them to a dedicated class so the controller stays clean:

php artisan make:request StoreProductRequest
public function rules(): array
{
    return [
        'name'  => 'required|string|max:255',
        'price' => 'required|integer|min:0',
        'stock' => 'required|integer|min:0',
    ];
}

When validation fails, Laravel automatically redirects the user back to the form with the error messages — no extra code needed.

6. A Simple Blade View

@foreach ($products as $product)
    <tr>
        <td>{{ $product->name }}</td>
        <td>{{ number_format($product->price) }}</td>
        <td>{{ $product->stock }}</td>
    </tr>
@endforeach

{{ $products->links() }}

The {{ $products->links() }} line renders pagination navigation automatically.

7. Update and Delete

Thanks to route model binding, Laravel finds the record by the ID in the URL for you:

public function update(StoreProductRequest $request, Product $product)
{
    $product->update($request->validated());
    return redirect()->route('products.index')
        ->with('success', 'Product updated.');
}

public function destroy(Product $product)
{
    $product->delete();
    return back()->with('success', 'Product deleted.');
}

Adding Search & Pagination

Real apps need search. Use when() so the filter only applies when a keyword is present:

$products = Product::query()
    ->when($request->q, fn($query) =>
        $query->where('name', 'like', '%'.$request->q.'%'))
    ->latest()
    ->paginate(10)
    ->withQueryString();

withQueryString() keeps the search term when moving between pages.

Common Mistakes to Avoid

  • Forgetting $fillable: causes a MassAssignmentException on create().
  • Skipping validation: dirty data reaches the database and opens security holes.
  • Putting all logic in the controller: use Form Requests and, for complex logic, a Service class.

With these seven steps you have a complete, safe, and clean CRUD. Repeat the same pattern for other entities such as customers, transactions, or categories — which is exactly why mastering CRUD makes every future build feel much faster.

Yudhi
Written by
Yudhi
Founder & Lead Developer, GudangCode

Yudhi is the founder of GudangCode and a Laravel developer who has built dozens of ready-to-use business information systems — from POS and HRIS to management apps. He writes guides and articles on GudangCode to help Indonesian developers run, understand, and deploy Laravel source code correctly.

LaravelPHPMySQLSistem Informasi Bisnis See all articles by Yudhi
Want the full source code & apps?

Sign up free to download ready-to-use business applications, information systems, and Laravel source code.

Sign Up Free & Download
Laravel PHP CRUD Tutorial
Share this article
Back to Blog
📚 Free Learning Hub

Learn Coding for Free at DhieCoderWeb

Explore Laravel, PHP, JavaScript tutorials, source code, web development guides, and practical programming tips.

DhieCoderWeb
100+
Tutorials
Free
Learning
SEO
Tips
Visit Dhiecoderweb.com →

Get Full Access Now!

Join our membership and unlock exclusive access to all premium features. Fast, easy, and ready to use instantly.

Join Membership Now
Tim Support
Online
Isi data dulu untuk mulai chat:
Beri rating & testimoni sebelum menutup:
Live chat by gudangcode.com