How to Import Data from Excel into a Database in Laravel

Importing data from an Excel file into a database is a very common need in business applications — from importing product data and employee data to transaction data. Laravel doesn'...

How to Import Data from Excel into a Database in Laravel

Importing data from an Excel file into a database is a very common need in business applications — from importing product data and employee data to transaction data. Laravel doesn't have this feature built in, but there is a popular package called Laravel Excel (by Maatwebsite) that is very easy to use and feature-rich. This tutorial will guide you from installation to importing with data validation.

Installing Laravel Excel

Install the package using Composer:

composer require maatwebsite/excel

For Laravel 11, the service provider and facade are registered automatically. For Laravel 10 and below, publish the optional configuration:

php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config

Make sure the following PHP extensions are enabled (they usually are by default):

  • php_zip
  • php_xml
  • php_gd2

Preparing the Model and Migration

Example use case: importing product data from Excel.

php artisan make:model Product -m
// Migration
public function up(): void
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('sku')->unique();
        $table->string('name');
        $table->string('category')->nullable();
        $table->decimal('price', 12, 2);
        $table->integer('stock')->default(0);
        $table->timestamps();
    });
}
php artisan migrate

Creating the Import Class

php artisan make:import ProductsImport --model=Product

Edit app/Imports/ProductsImport.php:

<?php

namespace App\Imports;

use App\Models\Product;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\SkipsErrors;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class ProductsImport implements
    ToModel,
    WithHeadingRow,
    WithValidation,
    SkipsOnError,
    WithBatchInserts,
    WithChunkReading
{
    use SkipsErrors;

    // Read the Excel file in chunks of 1000 rows to save memory
    public function chunkSize(): int
    {
        return 1000;
    }

    // Insert into the DB in batches
    public function batchSize(): int
    {
        return 500;
    }

    public function model(array $row): ?Product
    {
        return new Product([
            'sku'      => trim($row['sku']),
            'name'     => trim($row['product_name']),
            'category' => $row['category'] ?? null,
            'price'    => (float) $row['price'],
            'stock'    => (int) $row['stock'],
        ]);
    }

    // Per-row validation
    public function rules(): array
    {
        return [
            'sku'          => 'required|string|max:50',
            'product_name' => 'required|string|max:255',
            'price'        => 'required',
            'stock'        => 'required|integer|min:0',
        ];
    }

    // Custom error messages
    public function customValidationMessages(): array
    {
        return [
            'sku.required'          => 'The SKU column is required.',
            'product_name.required' => 'The product name column is required.',
            'price.required'        => 'The price column is required.',
        ];
    }
}

Creating the Controller and Route

php artisan make:controller ImportController
<?php

namespace App\Http\Controllers;

use App\Imports\ProductsImport;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;

class ImportController extends Controller
{
    public function index()
    {
        return view('import.index');
    }

    public function store(Request $request)
    {
        $request->validate([
            'file' => 'required|file|mimes:xlsx,xls,csv|max:10240',
        ]);

        $import = new ProductsImport();

        Excel::import($import, $request->file('file'));

        $failures = $import->failures();
        $errors   = $import->errors();

        if ($failures->isNotEmpty() || ! empty($errors)) {
            $errorMessages = [];

            foreach ($failures as $failure) {
                $errorMessages[] = "Row {$failure->row()}: " . implode(', ', $failure->errors());
            }

            return back()->with('import_errors', $errorMessages)
                         ->with('warning', 'Import finished with some errors.');
        }

        return back()->with('success', 'Data imported successfully!');
    }
}
// routes/web.php
use App\Http\Controllers\ImportController;

Route::get('/import', [ImportController::class, 'index'])->name('import.index');
Route::post('/import', [ImportController::class, 'store'])->name('import.store');

Creating the Upload Form View

<!-- resources/views/import/index.blade.php -->
@if(session('success'))
    <div style="color:green">{{ session('success') }}</div>
@endif

@if(session('warning'))
    <div style="color:orange">{{ session('warning') }}</div>
    <ul>
        @foreach(session('import_errors', []) as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif

<form action="{{ route('import.store') }}" method="POST" enctype="multipart/form-data">
    @csrf
    <p>File format: .xlsx or .csv</p>
    <p>Required columns: sku, product_name, category, price, stock</p>
    <input type="file" name="file" accept=".xlsx,.xls,.csv">
    @error('file') <p style="color:red">{{ $message }}</p> @enderror
    <button type="submit">Import Now</button>
</form>

Excel Template Format

Make sure the uploaded Excel file has the first row as the header (because we use WithHeadingRow). Example column structure:

  • Column A: sku
  • Column B: product_name
  • Column C: category
  • Column D: price
  • Column E: stock

Laravel Excel automatically converts the header to lowercase and replaces spaces with underscores.

Conclusion

With the Laravel Excel package, importing data from an Excel file becomes very easy and structured. Use WithChunkReading and WithBatchInserts for large files so you don't run into memory exhaustion. Always include validation and error handling so the user gets clear information if any rows have problems. You can also extend this feature by adding data export using the same class from Laravel Excel.

import excel laravel laravel excel maatwebsite excel upload excel laravel import csv laravel laravel import database
Share this article
Back to Blog
🚀 Partner Recommendation

Need Premium Source Code & Business Apps?

Access Laravel applications, POS systems, School Management, Clinic Software, ERP solutions, and ready-to-use premium source code at GudangCode.

GudangCode
  • ✔ Premium Source Code
  • ✔ Ready-to-Use Systems
  • ✔ Lifetime Updates
  • ✔ Lifetime Membership
  • ✔ Daily App Updates
Join Membership →