How to Upload Images in Laravel 12: A Step-by-Step Guide
Welcome to this comprehensive guide on uploading images in Laravel 12! Whether you're building a blog, an e-commerce site, or a social media platform, handling image uploads is a common requirement. In this tutorial, I’ll walk you through the entire process—from setting up your Laravel project to displaying the uploaded images on your website. We’ll use simple language and detailed explanations to ensure you understand each step.
By the end of this guide, you’ll be able to:
- Set up a Laravel 12 project for image uploads
- Create a model and migration to store image details
- Build a controller to handle uploads and display images
- Define routes for the upload form and submission
- Create a Blade template for the upload form
- Validate and store uploaded images
- Display the uploaded images on your website
Let’s get started!
Prerequisites
- A Laravel 12 project set up. If you don’t have one, create a new project using Composer:
composer create-project laravel/laravel your-project-name "12.*"
- A database connection configured in your
.envfile. Laravel 12 supports MySQL, PostgreSQL, SQLite, and more. - Basic knowledge of Laravel concepts like models, controllers, and routes.
If you’re new to Laravel, don’t worry—I’ll explain everything as we go along.
Step 1: Create a Model and Migration
To store information about the uploaded images, we need a model and a corresponding database table. Let’s create an Image model and a migration to define the table structure.
Run this command in your terminal:
php artisan make:model Image -m
This generates two files:
app/Models/Image.php: The model file.database/migrations/xxxx_xx_xx_create_images_table.php: The migration file (the timestamp will vary).
Open the migration file and update the up method to define the table columns:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateImagesTable extends Migration
{
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->id();
$table->string('path'); // To store the image file path
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('images');
}
}
This creates an images table with:
- An
idcolumn for unique identification. - A
pathcolumn to store the file path of the uploaded image. - Timestamps (
created_atandupdated_at) to track when records are added or modified.
Run the migration to create the table in your database:
php artisan migrate
Step 2: Create a Controller
Next, we need a controller to handle the logic for uploading and displaying images. Create an ImageController with this command:
php artisan make:controller ImageController
This creates a file at app/Http/Controllers/ImageController.php. Open it and add two methods:
index: To display the upload form and list of uploaded images.upload: To handle the image upload process.
Here’s the initial structure:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Image;
class ImageController extends Controller
{
public function index()
{
// Logic to display images
}
public function upload(Request $request)
{
// Logic to handle image upload
}
}
We’ll fill in these methods later.
Step 3: Define Routes
Routes tell Laravel how to handle incoming requests. We need two routes:
- A GET route to display the upload form and images.
- A POST route to handle the form submission and upload the image.
Open routes/web.php and add these routes:
use App\Http\Controllers\ImageController;
Route::get('/images', [ImageController::class, 'index'])->name('images.index');
Route::post('/images', [ImageController::class, 'upload'])->name('images.upload');
These routes:
- Map
GET /imagesto theindexmethod for displaying the form and images. - Map
POST /imagesto theuploadmethod for processing the upload.
Step 4: Create the Upload Form
Now, let’s create a Blade template for the upload form. Blade is Laravel’s templating engine, allowing us to mix HTML with dynamic content.
Create a new file at resources/views/images/index.blade.php and add this code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Upload</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1>Upload an Image</h1>
@if(session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
<form action="{{ route('images.upload') }}" method="POST" enctype="multipart/form-data" class="mb-5">
@csrf
<div class="form-group">
<label for="image">Select Image</label>
<input type="file" name="image" id="image" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary mt-2">Upload</button>
</form>
<h2>Uploaded Images</h2>
<div class="row">
<!-- Images will be displayed here -->
</div>
</div>
</body>
</html>
Key points:
- We use Bootstrap for styling.
- The form includes
enctype="multipart/form-data", which is essential for file uploads. @csrfadds a CSRF token for security.- The input field lets users select an image file.
Step 5: Handle the Image Upload
Let’s implement the upload method in ImageController to process the uploaded image. Update it like this:
use Illuminate\Http\Request;
use App\Models\Image;
use Illuminate\Support\Facades\Storage;
public function upload(Request $request)
{
// Validate the uploaded file
$request->validate([
'image' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048', // Max 2MB
]);
// Store the image in the 'public' disk
$path = $request->file('image')->store('images', 'public');
// Save the image path to the database
$image = new Image();
$image->path = $path;
$image->save();
// Redirect back with a success message
return redirect()->route('images.index')->with('success', 'Image uploaded successfully!');
}
This code does the following:
- Validation: Ensures the file is an image (JPEG, PNG, JPG, or GIF) and under 2MB.
- Storage: Saves the image to
storage/app/public/imagesusing the public disk. - Database: Stores the file path in the
imagestable. - Redirect: Returns the user to the
/imagespage with a success message.
Step 6: Display Uploaded Images
Now, update the index method to retrieve and display the uploaded images:
public function index()
{
$images = Image::latest()->get();
return view('images.index', compact('images'));
}
This fetches all images from the database (newest first) and passes them to the index.blade.php view.
Next, update the Blade template to display the images. Add this inside the <div class="row"> element:
@foreach($images as $image)
<div class="col-md-4 mb-3">
<img src="{{ asset('storage/' . $image->path) }}" alt="Uploaded Image" class="img-fluid">
</div>
@endforeach
This loop displays the images in a responsive grid. The asset helper generates the correct URL for each image.
Step 7: Link Storage for Public Access
To make uploaded images accessible via the browser, create a symbolic link from public/storage to storage/app/public. Run this command:
php artisan storage:link
This allows files in storage/app/public to be accessed publicly (e.g., at /storage/images/your-image.jpg).
Step 8: Test Your Application
Let’s test everything:
- Start your Laravel server:
php artisan serve
- Visit
http://localhost:8000/imagesin your browser. - Select an image and click "Upload."
- Check for a success message and verify the image appears below the form.
If something doesn’t work, ensure that:
- The storage directory is writable.
- The
storage:linkcommand ran successfully. - Your image meets the validation rules (file type and size).
Best Practices and Tips
- Validation: Always validate file uploads to ensure security and data consistency.
- Error Handling: Add logic to handle upload failures (e.g., file too large).
- Image Resizing: Consider resizing large images server-side for better performance.
- Multiple Uploads: Modify the form and controller to support multiple files if needed.
- Security: Restrict uploads to safe file types to prevent malicious uploads.
Conclusion
Congratulations! You’ve built a complete image upload system in Laravel 12. You learned how to set up a model and migration, create a controller and routes, design an upload form, handle file storage, and display images on your site.
This is a solid starting point—you can expand it further by adding features like image deletion, editing, or linking images to other models (e.g., users or products). If you have questions or run into issues, feel free to leave a comment. Happy coding with Laravel!
Projects to explore next
Source-code projects from the KritiMyantra catalogue. Check each project's details before buying.
Flask Authentication System (Free Version) - Kritim Yantra
🛠 Features✔ Google & GitHub Authentication✔ User Registration & Login✔ Profile/Dashboard Access✔ Secure & Mi...
Flask Blog CMS with Admin Dashboard — Python Source Code
A Flask-based blogging website with a built-in admin dashboard. Manage articles, images, categories, tags and featured p...
Laravel 12 + ReactJS Starter Kit: Add Multi-Language Support (Arabic, English, Spanish) with Blog CRUD
🚀 Installation & Setup Download & Extract Get the ZIP from kritimyantra.com and extract it. Includes preconfigu...
Comments
No comments yet. Be the first to comment.
Sign in to join the discussion.