Using Eloquent with Pagination in Laravel

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:

  1. Fetches only 10 records per page
  2. Automatically calculates the number of pages
  3. Generates navigation links
  4. 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:

  1. Executes a SQL query with LIMIT and OFFSET
  2. Counts the total number of records
  3. Calculates the number of pages
  4. Creates a paginator object
  5. Passes pagination metadata:
    • Total items
    • Items per page
    • Current page
    • Last page
    • Next and previous links
  6. Stores this in a LengthAwarePaginator class
  7. 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:

  1. paginate()
  2. simplePaginate()
  3. 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:

  1. Always use indexed columns for sorting
  2. Avoid using paginate() on unsorted records
  3. Use cursorPaginate() for very large tables
  4. Use eager loading for relational queries
  5. 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() before paginate()
  • 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

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *