Introduction
Pagination is one of the essential features in any modern web application that displays large datasets. Whether you are building an e-commerce product listing page, a blog article list, an admin panel with user records, or any searchable and filterable list, you will always need pagination. Laravel makes this process incredibly simple using Eloquent Pagination. With only one line of code, you can paginate thousands of records from the database and produce fully styled navigation links in your Blade templates.
In this comprehensive 3000-word guide, we will dive deep into how Eloquent pagination works, how to use it effectively, the different pagination methods Laravel offers, how pagination interacts with query builders, how to customize pagination styles, how to use pagination with relationships, filters, sorting, and search conditions, and how to optimize pagination for performance in real-world applications.
This post will take you from the basics of pagination to advanced and professional-level usage suitable for production applications.
Understanding What Pagination Is and Why It’s Needed
Pagination divides large datasets into smaller chunks called pages. Instead of loading thousands of records at once, pagination fetches only a small set of records, such as 10, 20, or 50 per page.
Benefits of pagination include:
- Improves performance by reducing SQL load
- Enhances user experience by avoiding large pages
- Reduces page load time significantly
- Saves memory and bandwidth
- Works seamlessly with sorting, filtering, and searching
- Helps create cleaner UI layouts
- Allows efficient navigation through datasets
Without pagination, large lists would slow down the server and the browser, making the application unusable.
Laravel’s pagination system solves all these issues elegantly.
Basic Example of Laravel Pagination Using Eloquent
You provided the simplest form of pagination:
Controller
$products = Product::paginate(10);
return view('products.index', compact('products'));
Blade
{{ $products->links() }}
This does the following:
- Fetches only 10 records per page
- Automatically calculates the number of pages
- Generates navigation links
- Produces clean HTML ready to display
Laravel takes care of URLs like:
/products?page=1/products?page=2/products?page=3
Everything works automatically.
How Pagination Works Internally in Laravel
When you call:
Product::paginate(10);
Laravel performs several tasks:
- Executes a SQL query with
LIMITandOFFSET - Counts the total number of records
- Calculates the number of pages
- Creates a paginator object
- Passes pagination metadata:
- Total items
- Items per page
- Current page
- Last page
- Next and previous links
- Stores this in a
LengthAwarePaginatorclass - Blade’s
links()method renders HTML navigation
This entire process is automated, making Laravel pagination extremely powerful and convenient.
Pagination Methods in Laravel
Laravel provides three main methods for pagination:
paginate()simplePaginate()cursorPaginate()
Each one serves different use cases.
Standard Pagination Using paginate()
This is the most common method.
Product::paginate(10);
This returns:
- Previous and next links
- Page numbers
- Total record count
- Last page number
Best for most applications.
Simple Pagination Using simplePaginate()
If you want faster pagination and do not need page numbers:
Product::simplePaginate(10);
This provides only:
- Next link
- Previous link
Use this when:
- Dataset is very large
- Page numbers do not matter
- Performance is critical
- Query is too expensive
Cursor-Based Pagination Using cursorPaginate()
Cursor pagination is ideal for extremely large datasets.
Product::orderBy('id')->cursorPaginate(10);
Characteristics:
- No OFFSET queries
- Faster than traditional pagination
- Ideal for infinite scrolling
- Works well with real-time data
- Uses unique ordering keys
This is used by large platforms for optimized scrolling feeds.
Displaying Pagination Links in Blade
Laravel provides a simple Blade directive:
{{ $products->links() }}
This outputs a fully rendered pagination component with:
- Previous page
- Next page
- Current page
- Surrounding pages
Laravel automatically detects your CSS framework (Bootstrap or Tailwind).
Customizing Pagination Styles
Laravel uses Tailwind CSS by default.
If you want Bootstrap pagination, add this in AppServiceProvider:
use Illuminate\Pagination\Paginator;
public function boot()
{
Paginator::useBootstrap();
}
Laravel then renders Bootstrap-style pagination.
Changing the Number of Pages Displayed
You can change how many pages surround the current page:
{{ $products->onEachSide(2)->links() }}
This displays:
- Two pages on each side of the current page
- Better navigation for large datasets
Adding Pagination to URL Routes
Your route may look like:
Route::get('/products', [ProductController::class, 'index']);
Pagination automatically appends:
?page=1
?page=2
?page=3
Laravel handles this for you.
Keeping Query Strings During Pagination
If you are filtering or searching:
/products?search=phone
To preserve this while paginating:
{{ $products->appends(request()->query())->links() }}
Now the page links will be:
/products?search=phone&page=2/products?search=phone&page=3
This is essential for search and filter systems.
Paginating With Filters and Conditions
You can paginate after performing query filters.
Controller
$query = Product::query();
if ($request->category) {
$query->where('category_id', $request->category);
}
if ($request->min_price) {
$query->where('price', '>=', $request->min_price);
}
$products = $query->paginate(10)->appends($request->query());
This gives:
- Filtering
- Searching
- Sorting
- Pagination
All combined in one elegant query.
Using Pagination With Search Results
Controller
$products = Product::where('name', 'like', "%{$request->search}%")
->paginate(10)
->appends(['search' => $request->search]);
Blade
{{ $products->links() }}
Maintains search keyword in pagination links.
Using Pagination With Sorting
Example sortable products page:
Controller
$products = Product::orderBy('price', 'asc')->paginate(10);
Sorting + pagination work together automatically.
Using Pagination With Eager Loading
If you need related data:
$products = Product::with('category')->paginate(10);
Then in Blade:
{{ $product->category->name }}
This avoids N+1 queries and improves performance.
Using Pagination With Joins
You can paginate after joining tables:
$products = Product::join('categories', 'products.category_id', '=', 'categories.id')
->select('products.*', 'categories.name as category')
->paginate(10);
Joins work perfectly with pagination.
Using Pagination With Grouping and Aggregate Data
Example:
$sales = Sale::select('product_id', DB::raw('sum(amount) as total'))
->groupBy('product_id')
->paginate(10);
Useful for reports and dashboards.
Paginating Custom Collections
Laravel can paginate manual collections too:
$collection = collect($data);
$paginated = $collection->paginate(10);
But generally, database pagination is recommended.
Accessing Pagination Data
The paginator object contains helpful methods:
$products->total();
$products->currentPage();
$products->lastPage();
$products->perPage();
$products->count();
$products->nextPageUrl();
$products->previousPageUrl();
This allows custom pagination UI.
Custom Pagination Views
You can publish pagination templates:
php artisan vendor:publish --tag=laravel-pagination
Edit them in:
resources/views/vendor/pagination
You can modify:
- Layout
- Colors
- Buttons
- Structure
Infinite Scroll Pagination (Load More Button)
Cursor pagination is ideal for infinite scrolling.
Controller
$products = Product::orderBy('id', 'asc')->cursorPaginate(10);
Blade
Use JavaScript to keep loading more records.
API Pagination
If building an API:
return Product::paginate(10);
Laravel automatically returns JSON:
{
"data": [...],
"links": {...},
"meta": {...}
}
API clients can navigate through pages easily.
Laravel Pagination and Performance Tips
To optimize pagination:
- Always use indexed columns for sorting
- Avoid using
paginate()on unsorted records - Use
cursorPaginate()for very large tables - Use eager loading for relational queries
- Avoid unnecessary joins
Optimized pagination leads to faster applications.
Paginating Soft Deleted Records
If using soft deletes:
Product::withTrashed()->paginate(10);
Product::onlyTrashed()->paginate(10);
Useful for admin restore systems.
Paginating Relationship Records
Example: show all orders of a user:
$orders = $user->orders()->paginate(10);
Blade:
{{ $orders->links() }}
This is how dashboards handle nested records.
Paginating Through Archives
Example: paginate blog posts by year:
Post::whereYear('created_at', $year)->paginate(10);
Pagination works seamlessly with date filters.
Customizing the Pagination Path
You can manually customize pagination URLs:
$products->withPath('/custom-products');
Result:
/custom-products?page=2
Using Pagination With Caching
For performance:
$products = Cache::remember('products_page_' . request('page'), 60, function () {
return Product::paginate(10);
});
This reduces database load.
Pagination With Custom Query Strings
{{ $products->appends(['sort' => 'price'])->links() }}
This helps maintain sorting during navigation.
Displaying Items Number Range
Show:
“Showing items 1 to 10 of 200”
{{ $products->firstItem() }}
{{ $products->lastItem() }}
{{ $products->total() }}
Great for admin dashboards.
Creating Your Own Pagination Component
You can build:
- Minimal pagination
- Button-only pagination
- Numeric-only pagination
By using:
@include('partials.pagination', ['paginator' => $products])
Handling Edge Cases
Edge cases include:
- Empty datasets
- High number of pages
- Very large records
- Filters returning no results
Example:
@if($products->count() == 0)
<p>No products found.</p>
@endif
Keeping Pagination State Across Sessions
You can store page number:
session(['product_page' => request('page')]);
And restore it later.
Using Pagination for Tables and Datatables
Laravel pagination works perfectly with:
- Datatables
- AlpineJS
- Livewire
- VueJS
- React
You can transform paginated JSON easily.
Livewire Pagination
public function render()
{
return view('livewire.products', [
'products' => Product::paginate(10),
]);
}
Livewire has built-in pagination support.
React and Vue Pagination Using Laravel API
Example API call:
axios.get('/api/products?page=3')
Frontend frameworks can easily use Laravel’s JSON pagination structure.
Full Practical Example: Product Listing Page
Controller
$products = Product::with('category')
->where('is_active', true)
->orderBy('created_at', 'desc')
->paginate(9)
->appends(request()->query());
return view('products.index', compact('products'));
Blade
@foreach($products as $product)
<div>{{ $product->name }}</div>
@endforeach
{{ $products->links() }}
This is a complete example you can use in production.
Common Mistakes When Using Pagination
Avoid these pitfalls:
- Calling
get()beforepaginate() - Forgetting to append search queries
- Using random ordering with pagination
- Using pagination inside loops
- Paginating very large joined tables without indexing
Best Practices for Using Pagination
Follow these guidelines:
- Always sort paginated results
- Use indexed columns for sorting
- Use eager loading for relationships
- Use
cursorPaginate()for huge data - Keep pagination logic inside controllers
- Avoid hardcoding page numbers
- Use appends for search and filtering
- Make pagination UI consistent across pages
Leave a Reply