Zum Hauptinhalt springen

Was ist Pagination

Die Pagination von Laravel ist in den Query Builder und das Eloquent ORM integriert und ohne Konfiguration einsatzbereit. Die aktuelle Seite wird automatisch aus dem Query-Parameter page des HTTP-Requests gelesen und den generierten Links auch automatisch hinzugefügt. Das Standard-HTML unterstützt Tailwind CSS; alternativ ist Bootstrap CSS verfügbar.

Drei Arten der Pagination

MethodeRückgabewertMerkmale
paginate()LengthAwarePaginatorErmittelt die Gesamtzahl. Erzeugt Seitenlinks mit Nummern
simplePaginate()PaginatorErmittelt keine Gesamtzahl. Nur „Zurück“ und „Weiter“
cursorPaginate()CursorPaginatorCursor-basiert. Ideal für große Datenmengen

Grundlagen

Pagination mit dem Query Builder

use Illuminate\Support\Facades\DB;

// 15 Einträge pro Seite
$users = DB::table('users')->paginate(15);

Pagination mit Eloquent

use App\Models\User;

$users = User::paginate(15);

// Mit Bedingung
$users = User::where('votes', '>', 100)->paginate(15);

simplePaginate

Wenn Sie die Gesamtzahl nicht benötigen (und nur „Zurück“- und „Weiter“-Links anzeigen), ist simplePaginate() effizienter.
$users = DB::table('users')->simplePaginate(15);
$users = User::where('active', true)->simplePaginate(15);
Wenn Sie keine Anzeige „X von insgesamt Y“ brauchen, wählen Sie simplePaginate(). paginate() führt zusätzlich eine COUNT(*)-Abfrage aus, simplePaginate() ist daher schneller.

cursorPaginate (Cursor-Pagination)

Cursor-Pagination verwendet statt eines OFFSET eine WHERE-Klausel und ist bei großen Datenmengen entsprechend performant. Für Infinite-Scroll-UIs besonders geeignet.
// orderBy ist erforderlich
$users = DB::table('users')->orderBy('id')->cursorPaginate(15);
$users = User::where('active', true)->cursorPaginate(15);
Statt einer Seitennummer enthält die erzeugte URL einen Cursor-String.
http://example.com/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
Für Cursor-Pagination ist orderBy erforderlich. Zudem muss die Sortierspalte zur paginierten Tabelle gehören.

OFFSET vs. Cursor

-- paginate() / simplePaginate() — verwendet OFFSET
SELECT * FROM users ORDER BY id ASC LIMIT 15 OFFSET 15;

-- cursorPaginate() — verwendet WHERE (Index kann greifen)
SELECT * FROM users WHERE id > 15 ORDER BY id ASC LIMIT 15;
Cursor-Pagination nutzt Indizes effektiv und ist auch dann stabil, wenn Datensätze häufig hinzugefügt oder gelöscht werden – Duplikate oder ausgelassene Einträge sind unwahrscheinlicher. Allerdings sind nummerierte Seitenlinks nicht möglich; nur „Zurück“ und „Weiter“.

Umsetzung im Controller

<?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'));
    }
}
<div class="container">
    @foreach ($users as $user)
        <p>{{ $user->name }}</p>
    @endforeach

    {{-- Pagination-Links ausgeben (Tailwind CSS) --}}
    {{ $users->links() }}
</div>
Die Methode links() erzeugt automatisch das HTML für die Seitenlinks. Standardmäßig werden drei Seiten vor und nach der aktuellen Seite angezeigt. Mit onEachSide() legen Sie fest, wie viele Links um die aktuelle Seite herum erscheinen.
{{-- Fünf Seiten vor und nach der aktuellen Seite --}}
{{ $users->onEachSide(5)->links() }}

Anzahl pro Seite aus dem Request übernehmen

public function index(Request $request): View
{
    $perPage = $request->integer('per_page', 15);
    $perPage = min(max($perPage, 1), 100); // auf 1–100 begrenzen

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

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

Mehrere Paginatoren auf einer Seite

Zeigen Sie zwei Paginatoren auf derselben Seite an, kollidiert die gemeinsame Nutzung des Parameters page. Über das dritte Argument können Sie den Parameternamen ändern.
$users = User::paginate(
    perPage: 15,
    columns: ['*'],
    pageName: 'users'
);

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

URL anpassen

Basis-URL ändern

$users = User::paginate(15);

// URLs im Format /admin/users?page=N erzeugen
$users->withPath('/admin/users');

Query-Parameter anhängen

// sort=votes an jeden Seitenlink anhängen
$users->appends(['sort' => 'votes']);

// Alle Query-Parameter des aktuellen Requests übernehmen
$users->withQueryString();

Hash-Fragment anhängen

// #users an das Ende der URL anhängen
$users->fragment('users');

API-Antworten (JSON)

Geben Sie einen Paginator direkt aus einer Route oder einem Controller zurück, wird er automatisch in JSON umgewandelt.
use App\Models\User;

Route::get('/api/users', function () {
    return User::paginate(15);
});
Das JSON-Format der Antwort:
{
    "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": "Max Mustermann" },
        { "id": 2, "name": "Erika Musterfrau" }
    ]
}

Kombination mit API-Ressourcen

Um das Ergebnis von paginate() in eine API-Ressourcen-Collection zu verpacken, übergeben Sie es an UserResource::collection().
use App\Http\Resources\UserResource;
use App\Models\User;

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

    return UserResource::collection($users);
});
Wenn Sie an UserResource::collection() einen Paginator übergeben, werden die Pagination-Informationen automatisch als Metadaten ergänzt.
Im JSON von cursorPaginate() stehen statt Seitennummern die Felder next_cursor und prev_cursor. API-Clients übergeben deren Werte als cursor-Parameter im nächsten Request.

Eigene Pagination-Views

In der View direkt angeben

{{-- Links über eine eigene View ausgeben --}}
{{ $paginator->links('vendor.pagination.custom') }}

{{-- Zusätzliche Daten übergeben --}}
{{ $paginator->links('vendor.pagination.custom', ['theme' => 'dark']) }}

Standard-View durch eigene Datei ersetzen

Veröffentlichen Sie zunächst die offiziellen Views und passen Sie sie an.
php artisan vendor:publish --tag=laravel-pagination
Dabei entstehen in resources/views/vendor/pagination/ u. a. folgende Dateien:
  • tailwind.blade.php — Standard (für Tailwind CSS)
  • bootstrap-5.blade.php — für Bootstrap 5
  • simple-tailwind.blade.php — für simplePaginate
Bearbeiten Sie tailwind.blade.php direkt oder erstellen Sie eine neue View und geben Sie sie im AppServiceProvider an.
use Illuminate\Pagination\Paginator;

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

Bootstrap CSS verwenden

Wenn Sie statt Tailwind Bootstrap nutzen möchten, konfigurieren Sie das in der Methode boot() des AppServiceProvider.
use Illuminate\Pagination\Paginator;

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

Paginator manuell erstellen

Um Pagination auf bereits vorhandene Daten (z. B. Arrays) anzuwenden, instanziieren Sie eine Paginator-Klasse direkt.
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()]
);

Häufig verwendete Instanzmethoden

$paginator = User::paginate(15);

$paginator->currentPage();     // Aktuelle Seitennummer
$paginator->lastPage();        // Letzte Seitennummer (bei simplePaginate nicht verfügbar)
$paginator->total();           // Gesamtzahl (bei simplePaginate nicht verfügbar)
$paginator->perPage();         // Anzahl pro Seite
$paginator->count();           // Anzahl auf der aktuellen Seite
$paginator->firstItem();       // Nummer des ersten Eintrags auf der aktuellen Seite
$paginator->lastItem();        // Nummer des letzten Eintrags auf der aktuellen Seite
$paginator->hasPages();        // Gibt es mehrere Seiten?
$paginator->hasMorePages();    // Gibt es eine nächste Seite?
$paginator->onFirstPage();     // Ist es die erste Seite?
$paginator->onLastPage();      // Ist es die letzte Seite?
$paginator->nextPageUrl();     // URL der nächsten Seite
$paginator->previousPageUrl(); // URL der vorherigen Seite
$paginator->url(3);            // URL von Seite 3
$paginator->items();           // Elemente der aktuellen Seite

Zusammenfassung

  • paginate() — wenn Gesamtzahl und nummerierte Seitenlinks nötig sind (typische Listenansichten)
  • simplePaginate() — wenn „Zurück“/„Weiter“-Links genügen (schneller)
  • cursorPaginate() — bei großen Datenmengen, Infinite Scroll oder häufigen Schreibvorgängen (beste Performance)
@foreach ($users as $user)
    <p>{{ $user->name }}</p>
@endforeach

{{ $users->links() }}
Übergeben Sie das Ergebnis von paginate() an die View und geben Sie mit links() die Seitenlinks aus. Die aktuelle Seite wird automatisch aus dem Query-Parameter page gelesen.
Ein direkt aus einer Route zurückgegebener Paginator wird automatisch in JSON umgewandelt. In Kombination mit API-Ressourcen geben Sie UserResource::collection($paginator) zurück. Die Antwort enthält data (das Datensatz-Array) und diverse Meta-Informationen.
Zuletzt geändert am 13. Juli 2026