ItSolutionStuff.com

Laravel 12 CRUD with Image Upload Tutorial

By Hardik Savani • April 30, 2025
Laravel

In this tutorial, you will discover step by step laravel 12 crud with image upload example.

CRUD stands for Create, Read, Update, and Delete, and it is a term used to describe the four basic operations that can be performed on data. CRUD is commonly used in computer programming, particularly in relation to databases and web applications, to refer to the fundamental actions that can be performed on a database or other data store.

We will create a product CRUD application using Laravel 12 in this example. We will create a products table with name, detail and image columns using Laravel 12 migration. Then, we will create routes, a controller, views, and model files for the product module. We will use Bootstrap 5 for design. Then we will create "images" folder in public folder to store images. So, let's follow the steps below to create CRUD operations with Laravel 12.

Preview:

laravel 12 crud and image upload

Step for Laravel 12 CRUD and Image Upload Example

  • Step 1: Install Laravel 12
  • Step 2: MySQL Database Configuration
  • Step 3: Create Migration
  • Step 4: Create Controller and Model
  • Step 5: Add Resource Route
  • Step 6: Add Blade Files
  • Run Laravel App

Step 1: Install Laravel 12

First of all, we need to get a fresh Laravel 12 version application using the command below because we are starting from scratch. So, open your terminal or command prompt and run the command below:

composer create-project laravel/laravel example-app

Step 2: MySQL Database Configuration

In Laravel 12, there is a default database connection using SQLite, but if we want to use MySQL instead, we need to add a MySQL connection with the database name, username, and password to the `.env` file.

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=here your database name(blog)
DB_USERNAME=here database username(root)
DB_PASSWORD=here database password(root)

Step 3: Create Migration

we are going to create crud application for product. so we have to create migration for "products" table using Laravel 12 php artisan command, so first fire bellow command:

php artisan make:migration create_products_table --create=products

After this command, you will find one file in the following path "database/migrations", and you have to put the below code in your migration file to create the products table.

<?php
  
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
  
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up(): void
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('detail');
            $table->string('image');
            $table->timestamps();
        });
    }
  
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down(): void
    {
        Schema::dropIfExists('products');
    }
};

Now you have to run this migration by following command:

php artisan migrate

Step 4: Add Controller and Model

In this step, now we should create a new controller named ProductController. In this controller, we write logic to store images. We store images in the "images" folder of the public folder. So, run the below command to create a new controller. The below controller is for creating a resource controller.

php artisan make:controller ProductController --resource --model=Product

After bellow command you will find new file in this path "app/Http/Controllers/ProductController.php".

In this controller will create seven methods by default as bellow methods:

1)index()

2)create()

3)store()

4)show()

5)edit()

6)update()

7)destroy()

So, let's copy bellow code and put on ProductController.php file.

app/Http/Controllers/ProductController.php

<?php
  
namespace App\Http\Controllers;
  
use App\Models\Product;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;
  
class ProductController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return response()
     */
    public function index(): View
    {
        $products = Product::latest()->paginate(5);
        
        return view('products.index',compact('products'))
                    ->with('i', (request()->input('page', 1) - 1) * 5);
    }
  
    /**
     * Show the form for creating a new resource.
     */
    public function create(): View
    {
        return view('products.create');
    }
  
    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request): RedirectResponse
    {
        $request->validate([
            'name' => 'required',
            'detail' => 'required',
            'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
        ]);
    
        $input = $request->all();
    
        if ($image = $request->file('image')) {
            $destinationPath = 'images/';
            $profileImage = date('YmdHis') . "." . $image->getClientOriginalExtension();
            $image->move($destinationPath, $profileImage);
            $input['image'] = "$profileImage";
        }
      
        Product::create($input);
       
        return redirect()->route('products.index')
                         ->with('success', 'Product created successfully.');
    }
  
    /**
     * Display the specified resource.
     */
    public function show(Product $product): View
    {
        return view('products.show', compact('product'));
    }
  
    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Product $product): View
    {
        return view('products.edit', compact('product'));
    }
  
    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Product $product): RedirectResponse
    {
        $request->validate([
            'name' => 'required',
            'detail' => 'required'
        ]);
    
        $input = $request->all();
    
        if ($image = $request->file('image')) {
            $destinationPath = 'images/';
            $profileImage = date('YmdHis') . "." . $image->getClientOriginalExtension();
            $image->move($destinationPath, $profileImage);
            $input['image'] = "$profileImage";
        }else{
            unset($input['image']);
        }
            
        $product->update($input);
      
        return redirect()->route('products.index')
                         ->with('success', 'Product updated successfully');
    }
  
    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Product $product): RedirectResponse
    {
        $product->delete();
         
        return redirect()->route('products.index')
                         ->with('success', 'Product deleted successfully');
    }
}

Okay, so after running the below command, you will find "app/Models/Product.php" and put the below content in Product.php file:

app/Models/Product.php

<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class Product extends Model
{
    use HasFactory;
  
    protected $fillable = [
        'name', 'detail', 'image'
    ];
}

Step 5: Add Resource Route

Here, we need to add a resource route for the product CRUD application. So, open your "routes/web.php" file and add the following route.

routes/web.php

<?php
  
use Illuminate\Support\Facades\Route;
  
use App\Http\Controllers\ProductController;
    
Route::resource('products', ProductController::class);

Step 6: Add Blade Files

In the last step, we have to create just blade files. So mainly, we have to create a layout file and then create a new folder "products", then create blade files of the CRUD app. So finally, you have to create the following blade files:

1) layout.blade.php

2) index.blade.php

3) create.blade.php

4) edit.blade.php

5) show.blade.php

So let's just create following file and put bellow code.

resources/views/products/layout.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>Laravel 12 CRUD with Image Upload Tutorial - ItSolutionStuff.com</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
</head>
<body>
      
<div class="container">
    @yield('content')
</div>
      
</body>
</html>

resources/views/products/index.blade.php

@extends('products.layout')
     
@section('content')
<div class="card mt-5">
  <h2 class="card-header">Laravel 12 CRUD with Image Upload Tutorial - ItSolutionStuff.com</h2>
  <div class="card-body">
          
        @session('success')
            <div class="alert alert-success" role="alert"> {{ $value }} </div>
        @endsession
  
        <div class="d-grid gap-2 d-md-flex justify-content-md-end">
            <a class="btn btn-success btn-sm" href="{{ route('products.create') }}"> <i class="fa fa-plus"></i> Create New Product</a>
        </div>
  
        <table class="table table-bordered table-striped mt-4">
            <thead>
                <tr>
                    <th width="80px">No</th>
                    <th>Image</th>
                    <th>Name</th>
                    <th>Details</th>
                    <th width="250px">Action</th>
                </tr>
            </thead>
  
            <tbody>
            @forelse ($products as $product)
                <tr>
                    <td>{{ ++$i }}</td>
                    <td><img src="/images/{{ $product->image }}" width="100px"></td>
                    <td>{{ $product->name }}</td>
                    <td>{{ $product->detail }}</td>
                    <td>
                        <form action="{{ route('products.destroy',$product->id) }}" method="POST">
             
                            <a class="btn btn-info btn-sm" href="{{ route('products.show',$product->id) }}"><i class="fa-solid fa-list"></i> Show</a>
              
                            <a class="btn btn-primary btn-sm" href="{{ route('products.edit',$product->id) }}"><i class="fa-solid fa-pen-to-square"></i> Edit</a>
             
                            @csrf
                            @method('DELETE')
                
                            <button type="submit" class="btn btn-danger btn-sm"><i class="fa-solid fa-trash"></i> Delete</button>
                        </form>
                    </td>
                </tr>
            @empty
                <tr>
                    <td colspan="5">There are no data.</td>
                </tr>
            @endforelse
            </tbody>
  
        </table>
        
        {!! $products->withQueryString()->links('pagination::bootstrap-5') !!}
  
  </div>
</div>      
@endsection

resources/views/products/create.blade.php

@extends('products.layout')
  
@section('content')
<div class="card mt-5">
  <h2 class="card-header">Add New Product</h2>
  <div class="card-body">
  
    <div class="d-grid gap-2 d-md-flex justify-content-md-end">
        <a class="btn btn-primary btn-sm" href="{{ route('products.index') }}"><i class="fa fa-arrow-left"></i> Back</a>
    </div>
  
    <form action="{{ route('products.store') }}" method="POST" enctype="multipart/form-data">
        @csrf
  
        <div class="mb-3">
            <label for="inputName" class="form-label"><strong>Name:</strong></label>
            <input 
                type="text" 
                name="name" 
                class="form-control @error('name') is-invalid @enderror" 
                id="inputName" 
                placeholder="Name">
            @error('name')
                <div class="form-text text-danger">{{ $message }}</div>
            @enderror
        </div>
  
        <div class="mb-3">
            <label for="inputDetail" class="form-label"><strong>Detail:</strong></label>
            <textarea 
                class="form-control @error('detail') is-invalid @enderror" 
                style="height:150px" 
                name="detail" 
                id="inputDetail" 
                placeholder="Detail"></textarea>
            @error('detail')
                <div class="form-text text-danger">{{ $message }}</div>
            @enderror
        </div>

        <div class="mb-3">
            <label for="inputImage" class="form-label"><strong>Image:</strong></label>
            <input 
                type="file" 
                name="image" 
                class="form-control @error('image') is-invalid @enderror" 
                id="inputImage">
            @error('image')
                <div class="form-text text-danger">{{ $message }}</div>
            @enderror
        </div>

        <button type="submit" class="btn btn-success"><i class="fa-solid fa-floppy-disk"></i> Submit</button>
    </form>
  
  </div>
</div>
@endsection

resources/views/products/edit.blade.php

@extends('products.layout')
     
@section('content')
<div class="card mt-5">
  <h2 class="card-header">Edit Product</h2>
  <div class="card-body">
  
    <div class="d-grid gap-2 d-md-flex justify-content-md-end">
        <a class="btn btn-primary btn-sm" href="{{ route('products.index') }}"><i class="fa fa-arrow-left"></i> Back</a>
    </div>
  
    <form action="{{ route('products.update',$product->id) }}" method="POST" enctype="multipart/form-data">
        @csrf
        @method('PUT')
  
        <div class="mb-3">
            <label for="inputName" class="form-label"><strong>Name:</strong></label>
            <input 
                type="text" 
                name="name" 
                value="{{ $product->name }}"
                class="form-control @error('name') is-invalid @enderror" 
                id="inputName" 
                placeholder="Name">
            @error('name')
                <div class="form-text text-danger">{{ $message }}</div>
            @enderror
        </div>
  
        <div class="mb-3">
            <label for="inputDetail" class="form-label"><strong>Detail:</strong></label>
            <textarea 
                class="form-control @error('detail') is-invalid @enderror" 
                style="height:150px" 
                name="detail" 
                id="inputDetail" 
                placeholder="Detail">{{ $product->detail }}</textarea>
            @error('detail')
                <div class="form-text text-danger">{{ $message }}</div>
            @enderror
        </div>

        <div class="mb-3">
            <label for="inputImage" class="form-label"><strong>Image:</strong></label>
            <input 
                type="file" 
                name="image" 
                class="form-control @error('image') is-invalid @enderror" 
                id="inputImage">
            <img src="/images/{{ $product->image }}" width="300px">
            @error('image')
                <div class="form-text text-danger">{{ $message }}</div>
            @enderror
        </div>

        <button type="submit" class="btn btn-success"><i class="fa-solid fa-floppy-disk"></i> Update</button>
    </form>
  
  </div>
</div>
@endsection

resources/views/products/show.blade.php

@extends('products.layout')
   
@section('content')
<div class="card mt-5">
  <h2 class="card-header">Show Product</h2>
  <div class="card-body">
  
    <div class="d-grid gap-2 d-md-flex justify-content-md-end">
        <a class="btn btn-primary btn-sm" href="{{ route('products.index') }}"><i class="fa fa-arrow-left"></i> Back</a>
    </div>
  
    <div class="row">
        <div class="col-xs-12 col-sm-12 col-md-12">
            <div class="form-group">
                <strong>Name:</strong> <br/>
                {{ $product->name }}
            </div>
        </div>
        <div class="col-xs-12 col-sm-12 col-md-12 mt-2">
            <div class="form-group">
                <strong>Details:</strong> <br/>
                {{ $product->detail }}
            </div>
        </div>
        <div class="col-xs-12 col-sm-12 col-md-12">
            <div class="form-group">
                <strong>Image:</strong><br/>
                <img src="/images/{{ $product->image }}" width="500px">
            </div>
        </div>
    </div>
  
  </div>
</div>
@endsection

Run Laravel App:

All the required steps have been done, now you have to type the given below command and hit enter to run the Laravel app:

php artisan serve

Now, Go to your web browser, type the given URL and view the app output:

http://localhost:8000/products

Make sure, you have created "images" folder in public directory

You will see layout as like bellow:

List Page:

Add Page:

Edit Page:

Show Page:

I hope it can help you....

Hardik Savani

Hardik Savani

I'm a full-stack developer, entrepreneur, and founder of ItSolutionStuff.com. Passionate about PHP, Laravel, JavaScript, and helping developers grow.

📺 Subscribe on YouTube

We Are Recommending You

How to Install and Configuration Telescope in Laravel 12?

Read Now →

Laravel 12 Google Recaptcha V3 Validation Tutorial

Read Now →

Laravel 12 Image Intervention Tutorial With Example

Read Now →

Laravel 12 User Roles and Permissions Tutorial

Read Now →

How to Create Event Calendar in Laravel 12?

Read Now →

Laravel 12 Summernote Image Upload Tutorial

Read Now →

How to use Multiple Database in Laravel 12?

Read Now →

Laravel 12 Generate and Read Sitemap XML File Tutorial

Read Now →

Laravel 12 Stripe Payment Gateway Integration Example

Read Now →

Laravel 12 Dynamic Google Charts Integration Tutorial

Read Now →

laravel 12 Socialite Login with Twitter / X Account Example

Read Now →

How to Get User Location using IP Address in Laravel 12?

Read Now →

Laravel 12 Drag and Drop File Upload with Dropzone JS

Read Now →