How to Build a Real-Time Live Search in Laravel 12 with AJAX and jQuery
How to Build a Real-Time Live Search in Laravel 12 with AJAX and jQuery
Live search, also known as instant search or autocomplete, allows users to see relevant results as they type into a search field. This reduces wait times and improves usability, leading to better engagement and lower bounce rates.
AJAX (Asynchronous JavaScript and XML) is the technology that enables this by allowing data to be sent to and retrieved from the server asynchronously, without reloading the page. In Laravel, AJAX pairs perfectly with routes and controllers to handle requests efficiently.
- Improved UX: Users get immediate results without page reloads.
- Efficiency: Only the necessary data is fetched from the server, reducing bandwidth and server load.
- SEO Boost: Faster, interactive pages can improve dwell time and overall engagement metrics.
In Laravel 12, enhancements like better routing, improved middleware, and optimized Eloquent queries make AJAX implementations smoother than ever. Laravel 12 requires PHP 8.2+ and offers improved error handling, which we will leverage throughout this tutorial.
By the end of this guide, you will have a fully working live search that queries a products table and displays results instantly as the user types.

Table Of Content
1 Prerequisites
- PHP ≥ 8.2
- Composer
- MySQL / PostgreSQL / SQLite (or any supported DB)
- Basic knowledge of Laravel routing, controllers, and Blade
2 Introduction
We will use Eloquent ORM for database queries, jQuery for AJAX calls, and Bootstrap for a clean UI. If you are new to Eloquent, check out our Laravel 12 Eloquent Tips and Tricks for Beginners guide first.
3 Create a Fresh Laravel 12 Project
3.1 Install Laravel Project
composer create-project laravel/laravel:^12.0 live-search
Navigate to your project directory:
cd live-search
3.2 Configure Your Database (.env)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=live_search_db
DB_USERNAME=root
DB_PASSWORD=
This setup ensures Laravel connects seamlessly to MySQL. In Laravel 12, database configurations are more flexible, supporting multiple connections out of the box.
4 Creating Migrations and Seeding Data
Migrations in Laravel allow version-controlled database schema management.
Generate Migration: Run
php artisan make:migration create_products_table
Edit Migration File database/migrations:
<?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('title');
$table->string('description');
$table->decimal('price', 10, 2);
$table->timestamps();
});
}
public function down(): void {
Schema::dropIfExists('products');
}
};
Run the migration:
php artisan migrate
Create the Product Model:
The controller references App\Models\Product, so we need to generate the Eloquent model:
php artisan make:model Product
This creates app/Models/Product.php. Laravel will automatically map it to the products table. No additional configuration is needed for this tutorial.
Create Seeder: Run
php artisan make:seeder ProductSeeder
Edit Seeder File database/seeders/ProductSeeder.php:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class ProductSeeder extends Seeder {
public function run(): void {
DB::table('products')->insert([
['title' => 'T-shirt', 'description' => 'A comfortable cotton t-shirt.', 'price' => 15.00],
['title' => 'Jeans', 'description' => 'Classic blue denim jeans.', 'price' => 45.50],
['title' => 'Laptop', 'description' => 'Powerful laptop for all your needs.', 'price' => 1200.00],
['title' => 'Keyboard', 'description' => 'Mechanical keyboard with RGB lighting.', 'price' => 75.25],
['title' => 'Mouse', 'description' => 'Ergonomic wireless mouse.', 'price' => 30.00],
]);
}
}
Update DatabaseSeeder.php: Add $this->call(ProductSeeder::class); inside the run() method.
Run Seeder:
php artisan db:seed
This populates your table with sample data. In real applications, use factories for larger datasets. Laravel 12's seeding is optimized for performance.
5 Building the Controller for Search Logic
php artisan make:controller SearchController
Edit app/Http/Controllers/SearchController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Product;
class SearchController extends Controller {
public function index() {
return view('search');
}
public function search(Request $request) {
$request->validate(['search' => 'nullable|string|max:255']);
if ($request->ajax()) {
$products = Product::where('title', 'like', '%' . $request->search . '%')->get();
$output = '';
if ($products->count() > 0) {
foreach ($products as $product) {
$output .= '<tr>' .
'<td>' . e($product->id) . '</td>' .
'<td>' . e($product->title) . '</td>' .
'<td>' . e($product->description) . '</td>' .
'<td>' . e($product->price) . '</td>' .
'</tr>';
}
} else {
$output .= '<tr><td colspan="4">No results found</td></tr>';
}
return response($output);
}
}
}
Explanation:
- The index method loads the Blade view.
- The search method checks for an AJAX request, then queries the products table using Eloquent's where...like for fuzzy matching.
- We wrap output values with Laravel's e() helper to escape HTML entities and prevent XSS attacks.
- Input validation with nullable|string|max:255 prevents invalid or oversized queries.
- The closing <?php ... ?> tag is omitted following PSR-12 coding standards.
For a deeper understanding of how Laravel handles requests and middleware, see our Laravel 12 Routing and Middleware Complete Guide.
6 Creating the Front-End View with jQuery AJAX
The view handles user input and displays results.
Create resources/views/search.blade.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="_token" content="{{ csrf_token() }}">
<title>Live Search in Laravel 12</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>
<body>
<div class="container mt-5">
<h3>Products Info</h3>
<input type="text" class="form-control" id="search" placeholder="Search products...">
<p id="search-status" class="text-muted mt-1" style="display:none;">Searching...</p>
<table class="table table-bordered table-hover mt-3">
<thead>
<tr>
<th>ID</th>
<th>Product Name</th>
<th>Description</th>
<th>Price</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')
}
});
let debounceTimer;
$('#search').on('keyup', function(){
let query = $(this).val();
clearTimeout(debounceTimer);
$('#search-status').show();
debounceTimer = setTimeout(function(){
$.ajax({
type: 'GET',
url: '{{ url("search") }}',
data: { search: query },
success: function(data){
$('tbody').html(data);
$('#search-status').hide();
},
error: function(){
$('tbody').html('<tr><td colspan="4">Something went wrong. Please try again.</td></tr>');
$('#search-status').hide();
}
});
}, 300);
});
</script>
</body>
</html>
Key improvements in this view:
- Bootstrap 5.3 instead of the outdated Bootstrap 3.3.6 and jQuery 3.7.1 (latest stable).
- Debounce (300ms): Instead of firing an AJAX request on every keystroke, we wait 300ms after the user stops typing. This drastically reduces server requests.
- Loading indicator: A "Searching..." message appears while the request is in progress.
- Error handling: The AJAX error callback shows a user-friendly message if the request fails.
- CSRF token is included via a meta tag for Laravel's built-in CSRF protection.
7 Define Routes
use App\Http\Controllers\SearchController;
Route::get('/', [SearchController::class, 'index']);
Route::get('/search', [SearchController::class, 'search']);
The first route maps the homepage to the index method (loads the Blade view). The second route maps /search to the search method which handles the AJAX query and returns results.
To learn more about route groups, named routes, and middleware layers in Laravel 12, visit our Laravel 12 Routing and Middleware Complete Guide.
8 Folder Structure
9 Run & Test the Application
php artisan serve
Visit: http://127.0.0.1:8000/
Type "Lap" in the search box — you should see "Laptop" appear instantly in the table.
Troubleshooting tips:
- Check the browser console (F12) for JavaScript errors.
- Verify your database connection in .env and ensure the products table has been seeded.
- Ensure the CSRF meta tag is present in the HTML head.
- If you see a 404 on /search, run php artisan route:list to verify your routes are registered.
- If you see a 500 error, check storage/logs/laravel.log for details.
For a list of the most common Laravel 12 errors and how to fix them, see our Common Laravel 12 Errors and How to Fix Them guide.
10 Conclusion
You have now implemented a fully working live search in Laravel 12 using AJAX, covering project setup, database migrations, seeding, Eloquent queries, a clean controller, and a responsive front-end with debounce and error handling.
This approach significantly improves user experience by providing instant feedback without page reloads. With clean routing, efficient Eloquent queries, and proper front-end handling, you can build fast, scalable real-time search features suitable for any Laravel application.
Next steps to explore:
- Add pagination to handle large result sets.
- Implement search across multiple columns (title + description).
- Use Laravel's built-in rate limiting to protect the search endpoint.
- Consider caching frequently searched queries with Redis for better performance.
Continue learning:
- Laravel 12 Performance Tips: Optimize Your App for Lightning-Fast Loading
- How to Build a REST API in Laravel 12: Step-by-Step Guide
- Laravel 12 Queue and Jobs Tutorial: Background Processing Made Easy
Related Laravel 12 Tutorials
If you found this tutorial helpful, check out these related Laravel 12 guides on our site:
- Laravel 12 Eloquent Tips and Tricks for Beginners — Master the ORM used in this tutorial to write cleaner, faster queries.
- Laravel 12 Routing and Middleware: Complete Guide — Deep dive into route groups, named routes, and middleware layers.
- How to Build a REST API in Laravel 12 — Learn to build full CRUD APIs with authentication.
- Laravel 12 Performance Tips: Optimize Your App — Caching, eager loading, queues, and more for production-ready apps.
- Common Laravel 12 Errors and How to Fix Them — Quick solutions for the most frequent Laravel 12 issues.
- Laravel 12 Queue and Jobs Tutorial — Offload heavy tasks like email sending and image processing to background queues.
- Step-by-Step Guide to Import CSV in Laravel 12 — Bulk data handling with upsertOrInsert().
Written by Revathi M
PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel
Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.
Frequently Asked Questions
Live search (also called instant search or autocomplete) in Laravel is a feature that displays matching database results in real time as the user types into a search field. It uses AJAX to send asynchronous requests to a Laravel controller, which queries the database with Eloquent and returns results without reloading the page.
Yes, this tutorial is built specifically for Laravel 12 and leverages its latest features including improved Eloquent performance, PHP 8.2+ support, and enhanced error handling.
You need PHP 8.2 or higher, Composer, a database server (MySQL, PostgreSQL, or SQLite), and basic familiarity with Laravel routing, controllers, and Blade templates.
When no matching products are found, the controller returns an HTML table row displaying "No results found" spanning all columns. This is handled by checking the Eloquent query result count in the SearchController.
You can improve performance by adding a debounce timer (e.g., 300ms) on the front end to reduce the number of AJAX requests, indexing the searched database columns, caching frequently searched terms with Redis, and using pagination to limit the number of results returned per query.
