Explicamos la paginación en Laravel: diferencias entre paginate(), simplePaginate() y cursorPaginate(), visualización en Blade, respuestas API y personalización de URL.
La paginación de Laravel se integra con el query builder y Eloquent ORM, y se puede usar sin configuración. La página actual se obtiene automáticamente del parámetro page de la solicitud HTTP y se añade también a los enlaces generados.El HTML por defecto es compatible con Tailwind CSS, y también hay opción para Bootstrap CSS.
Si no necesitas mostrar “X de N en total”, elige simplePaginate(). paginate() ejecuta un COUNT(*) adicional, por lo que simplePaginate() es más rápido.
-- paginate() / simplePaginate() — usa OFFSETSELECT * FROM users ORDER BY id ASC LIMIT 15 OFFSET 15;-- cursorPaginate() — usa WHERE (aprovecha los índices)SELECT * FROM users WHERE id > 15 ORDER BY id ASC LIMIT 15;
La paginación por cursor aprovecha los índices y evita mejor la duplicación/omisión de registros cuando hay muchas inserciones/eliminaciones. Sin embargo, no genera enlaces por número de página, solo “anterior/siguiente”.
<div class="container"> @foreach ($users as $user) <p>{{ $user->name }}</p> @endforeach</div>{{-- Muestra los enlaces (compatibles con Tailwind CSS) --}}{{ $users->links() }}
links() genera automáticamente el HTML de los enlaces. Muestra tres páginas a cada lado de la actual.
Para envolver el resultado de paginate() en una colección de recurso, pásaselo a UserResource::collection().
use App\Http\Resources\UserResource;use App\Models\User;Route::get('/api/users', function () { $users = User::paginate(15); return UserResource::collection($users);});
Al pasar el paginador a UserResource::collection(), la información de paginación se añade automáticamente como metadatos.
El JSON de cursorPaginate() incluye next_cursor y prev_cursor en lugar de números de página. El cliente API usa esos valores como parámetro cursor en la siguiente solicitud.
{{-- Muestra los enlaces con una vista personalizada --}}{{ $paginator->links('vendor.pagination.custom') }}{{-- Pasar datos adicionales --}}{{ $paginator->links('vendor.pagination.custom', ['theme' => 'dark']) }}
Puedes editar tailwind.blade.php directamente o crear una nueva vista e indicarla en AppServiceProvider.
use Illuminate\Pagination\Paginator;public function boot(): void{ Paginator::defaultView('vendor.pagination.custom'); Paginator::defaultSimpleView('vendor.pagination.simple-custom');}
$paginator = User::paginate(15);$paginator->currentPage(); // Página actual$paginator->lastPage(); // Última página (no en simplePaginate)$paginator->total(); // Total (no en simplePaginate)$paginator->perPage(); // Elementos por página$paginator->count(); // Elementos en la página actual$paginator->firstItem(); // Índice del primer elemento$paginator->lastItem(); // Índice del último elemento$paginator->hasPages(); // ¿Hay más de una página?$paginator->hasMorePages(); // ¿Hay página siguiente?$paginator->onFirstPage(); // ¿Estamos en la primera?$paginator->onLastPage(); // ¿Estamos en la última?$paginator->nextPageUrl(); // URL de la siguiente$paginator->previousPageUrl(); // URL de la anterior$paginator->url(3); // URL de la página 3$paginator->items(); // Array de elementos actuales
paginate() — cuando necesitas total y enlaces numerados (pantallas de listado habituales)
simplePaginate() — cuando basta con “anterior/siguiente” (más rápido)
cursorPaginate() — para grandes volúmenes, scroll infinito o mucha escritura (máximo rendimiento)
Patrón básico en Blade
@foreach ($users as $user) <p>{{ $user->name }}</p>@endforeach{{ $users->links() }}
Pasa el resultado de paginate() a la vista y muestra los enlaces con links().
La página actual se detecta automáticamente desde el parámetro page.
Paginación en la API
Devolver el paginador desde la ruta lo convierte automáticamente a JSON.
Para combinarlo con API Resources, devuelve UserResource::collection($paginator).
La respuesta contiene data (registros) y varios campos de metadatos.