> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Learn about Laravel's pagination feature. Covers the differences between paginate(), simplePaginate(), and cursorPaginate(); Blade rendering; API responses; and URL customization.

## What is pagination

Laravel's pagination is integrated with the query builder and Eloquent ORM, so you can start using it without any configuration. The current page is automatically detected from the `page` query parameter on the HTTP request and is also automatically appended to the generated links.

The default HTML supports Tailwind CSS, and Bootstrap CSS is available as an option.

## Three pagination methods

| Method             | Return type            | Characteristics                                       |
| ------------------ | ---------------------- | ----------------------------------------------------- |
| `paginate()`       | `LengthAwarePaginator` | Fetches total count. Generates numbered page links    |
| `simplePaginate()` | `Paginator`            | Doesn't fetch total count. "Previous" and "Next" only |
| `cursorPaginate()` | `CursorPaginator`      | Cursor-based. Ideal for large datasets                |

## Basic usage

### Query builder pagination

```php theme={null}
use Illuminate\Support\Facades\DB;

// Retrieve 15 records per page
$users = DB::table('users')->paginate(15);
```

### Eloquent pagination

```php theme={null}
use App\Models\User;

$users = User::paginate(15);

// With conditions
$users = User::where('votes', '>', 100)->paginate(15);
```

### simplePaginate

When you don't need a total-count query (displaying only "Previous" and "Next" links), `simplePaginate()` is more efficient.

```php theme={null}
$users = DB::table('users')->simplePaginate(15);
$users = User::where('active', true)->simplePaginate(15);
```

<Tip>
  Choose `simplePaginate()` when you don't need to display "X of Y total." `paginate()` runs an additional `COUNT(*)` query, so `simplePaginate()` is faster.
</Tip>

### cursorPaginate (cursor pagination)

Cursor pagination uses a WHERE clause instead of OFFSET, delivering high performance on large datasets. It's especially well-suited to infinite-scroll UIs.

```php theme={null}
// orderBy is required
$users = DB::table('users')->orderBy('id')->cursorPaginate(15);
$users = User::where('active', true)->cursorPaginate(15);
```

The generated URLs contain a cursor string instead of a page number.

```
http://example.com/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
```

<Warning>
  `orderBy` is required to use cursor pagination. Also, the sorting columns must belong to the table you're paginating.
</Warning>

### OFFSET vs cursor comparison

```sql theme={null}
-- paginate() / simplePaginate() — uses OFFSET
SELECT * FROM users ORDER BY id ASC LIMIT 15 OFFSET 15;

-- cursorPaginate() — uses WHERE (index-friendly)
SELECT * FROM users WHERE id > 15 ORDER BY id ASC LIMIT 15;
```

Cursor pagination makes effective use of indexes and is much less likely to duplicate or skip records even when data is frequently added or removed. However, it cannot generate numbered page links—only "Previous" and "Next."

## Controller implementation

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\View\View;

class UserController extends Controller
{
    public function index(): View
    {
        $users = User::orderBy('name')->paginate(20);

        return view('users.index', compact('users'));
    }
}
```

## Displaying pagination links in Blade

```blade theme={null}
<div class="container">
    @foreach ($users as $user)
        <p>{{ $user->name }}</p>
    @endforeach
</div>

{{-- Output pagination links (Tailwind CSS-compatible) --}}
{{ $users->links() }}
```

The `links()` method automatically generates HTML for the page links. It shows three pages before and three pages after the current page.

### Adjusting the number of visible links

Use `onEachSide()` to change how many page links to show before and after the current page.

```blade theme={null}
{{-- Display 5 pages on each side of the current page --}}
{{ $users->onEachSide(5)->links() }}
```

## Accepting per-page count from the request

```php theme={null}
public function index(Request $request): View
{
    $perPage = $request->integer('per_page', 15);
    $perPage = min(max($perPage, 1), 100); // Clamp to 1–100

    $users = User::paginate($perPage);

    return view('users.index', compact('users'));
}
```

## Displaying multiple paginators on one page

When displaying two paginators on the same screen, both using `page` conflicts. Change the parameter name via the third argument.

```php theme={null}
$users = User::paginate(
    perPage: 15,
    columns: ['*'],
    pageName: 'users'
);

$posts = Post::paginate(
    perPage: 10,
    columns: ['*'],
    pageName: 'posts'
);
```

## Customizing URLs

### Changing the base URL

```php theme={null}
$users = User::paginate(15);

// Generate URLs in /admin/users?page=N form
$users->withPath('/admin/users');
```

### Appending query parameters

```php theme={null}
// Add sort=votes to every page link
$users->appends(['sort' => 'votes']);

// Carry over all query parameters from the current request
$users->withQueryString();
```

### Appending a hash fragment

```php theme={null}
// Add #users to the end of the URL
$users->fragment('users');
```

## API responses (JSON output)

If you return a paginator directly from a route or controller, it's automatically converted to JSON.

```php theme={null}
use App\Models\User;

Route::get('/api/users', function () {
    return User::paginate(15);
});
```

The response's JSON format:

```json theme={null}
{
    "total": 50,
    "per_page": 15,
    "current_page": 1,
    "last_page": 4,
    "first_page_url": "http://example.com/api/users?page=1",
    "last_page_url": "http://example.com/api/users?page=4",
    "next_page_url": "http://example.com/api/users?page=2",
    "prev_page_url": null,
    "path": "http://example.com/api/users",
    "from": 1,
    "to": 15,
    "data": [
        { "id": 1, "name": "Taro Yamada" },
        { "id": 2, "name": "Hanako Suzuki" }
    ]
}
```

### Combining with API resources

To wrap a `paginate()` result with an API resource collection, pass it to `UserResource::collection()`.

```php theme={null}
use App\Http\Resources\UserResource;
use App\Models\User;

Route::get('/api/users', function () {
    $users = User::paginate(15);

    return UserResource::collection($users);
});
```

When you pass a paginator to `UserResource::collection()`, pagination information is automatically added as metadata.

<Info>
  The JSON for `cursorPaginate()` includes `next_cursor` and `prev_cursor` instead of page numbers. API clients use these values as the `cursor` parameter on the next request.
</Info>

## Custom pagination views

### Specifying a view file directly

```blade theme={null}
{{-- Output links with a custom view --}}
{{ $paginator->links('vendor.pagination.custom') }}

{{-- Pass extra data --}}
{{ $paginator->links('vendor.pagination.custom', ['theme' => 'dark']) }}
```

### Changing the default view to a custom file

First publish the official views and then customize.

```shell theme={null}
php artisan vendor:publish --tag=laravel-pagination
```

The following files are generated in `resources/views/vendor/pagination/`:

* `tailwind.blade.php` — Default (for Tailwind CSS)
* `bootstrap-5.blade.php` — For Bootstrap 5
* `simple-tailwind.blade.php` — For simplePaginate
* ...

Edit `tailwind.blade.php` directly, or create a new view and specify it in `AppServiceProvider`.

```php theme={null}
use Illuminate\Pagination\Paginator;

public function boot(): void
{
    Paginator::defaultView('vendor.pagination.custom');
    Paginator::defaultSimpleView('vendor.pagination.simple-custom');
}
```

### Using Bootstrap CSS

To use Bootstrap instead of Tailwind, configure it in `AppServiceProvider`'s `boot()`.

```php theme={null}
use Illuminate\Pagination\Paginator;

public function boot(): void
{
    Paginator::useBootstrapFive(); // Bootstrap 5
    // Paginator::useBootstrapFour(); // Bootstrap 4
}
```

## Manually creating a paginator

To apply pagination to existing data such as an array, instantiate the paginator class directly.

```php theme={null}
use Illuminate\Pagination\LengthAwarePaginator;

$items = collect(range(1, 200))->map(fn ($i) => ['id' => $i, 'name' => "Item {$i}"]);

$perPage = 15;
$currentPage = request()->integer('page', 1);

$paginator = new LengthAwarePaginator(
    items: $items->forPage($currentPage, $perPage),
    total: $items->count(),
    perPage: $perPage,
    currentPage: $currentPage,
    options: ['path' => request()->url()]
);
```

## Commonly used instance methods

```php theme={null}
$paginator = User::paginate(15);

$paginator->currentPage();     // Current page number
$paginator->lastPage();        // Last page number (not available on simplePaginate)
$paginator->total();           // Total record count (not available on simplePaginate)
$paginator->perPage();         // Records per page
$paginator->count();           // Records on the current page
$paginator->firstItem();       // Index of the first item on the current page
$paginator->lastItem();        // Index of the last item on the current page
$paginator->hasPages();        // Whether multiple pages exist
$paginator->hasMorePages();    // Whether there's a next page
$paginator->onFirstPage();     // Whether this is the first page
$paginator->onLastPage();      // Whether this is the last page
$paginator->nextPageUrl();     // URL of the next page
$paginator->previousPageUrl(); // URL of the previous page
$paginator->url(3);            // URL of page 3
$paginator->items();           // Array of items on the current page
```

## Summary

<AccordionGroup>
  <Accordion title="How to choose a pagination method">
    * **`paginate()`** — when you need total count and numbered page links (typical list screens)
    * **`simplePaginate()`** — when "Previous" and "Next" only is sufficient (faster)
    * **`cursorPaginate()`** — for large datasets, infinite scroll, or when data is written frequently (highest performance)
  </Accordion>

  <Accordion title="Basic Blade display pattern">
    ```blade theme={null}
    @foreach ($users as $user)
        <p>{{ $user->name }}</p>
    @endforeach

    {{ $users->links() }}
    ```

    Just pass the result of `paginate()` to the view and use `links()` to output page links.
    The current page is automatically detected from the `page` query parameter.
  </Accordion>

  <Accordion title="Pagination in APIs">
    Returning a paginator directly from a route automatically converts it to JSON.
    To combine with API resources, return `UserResource::collection($paginator)`.
    The response includes `data` (an array of records) and various metadata fields.
  </Accordion>
</AccordionGroup>


## Related topics

- [Laravel Scout](/en/scout.md)
- [Upgrade guide: Laravel 12 to 13](/en/blog/upgrade-12-to-13.md)
- [Eloquent API resources](/en/eloquent-resources.md)
- [⚡ Getting started with Livewire 4 — reactive UIs without JavaScript](/en/blog/livewire-introduction.md)
