“📌 The Ultimate Guide to Pagination in Laravel: Offset, Cursor, Keyset, Time-Based & Hybrid Explained” 🚀
Pagination is an essential feature in web applications, ensuring that large datasets are efficiently managed and displayed. Laravel provides multiple pagination methods, each with its own advantages and use cases. In this post, we’ll explore the different types of pagination in Laravel, their pros and cons, and when to use them.
1. Offset-Based Pagination (Traditional Pagination):
This is the most common pagination method in Laravel, where you fetch a specific page using an OFFSET
and LIMIT
.
$users = User::orderBy('id')->paginate(10);
// generated sql
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 10;
// Example URL:
/users?page=2
If you need custom pagination logic, you can use
skip()
(offset) andtake()
(limit).
$page = request()->input('page', 1);
$limit = 10;
$offset = ($page - 1) * $limit;
$users = User::skip($offset)->take($limit)->get();
//generated sql
SELECT * FROM users LIMIT 10 OFFSET 10;
2. Cursor-Based Pagination (Keyset Pagination):
Cursor pagination is more efficient than offset pagination as it avoidsOFFSET
and instead uses a WHERE clause with a unique key.
$users = User::orderBy('id')->cursorPaginate(10);
// generated sql
SELECT * FROM users WHERE id > ? ORDER BY id ASC LIMIT 10;
//example url
/users?cursor=eyJpZCI6MTA= // Encoded cursor
If you want more control, you can implement cursor-based pagination manually.
For example : paginate users list using created date
$limit = 10;
$cursor = request('cursor'); // Get cursor from request (e.g., last seen created_at)
$query = User::orderBy('created_at', 'asc');
if ($cursor) {
$query->where('created_at', '>', $cursor);
}
$users = $query->limit($limit)->get();
//next page link
$nextCursor = $users->last()?->created_at;
$nextPageUrl = url('/users?cursor=' . urlencode($nextCursor));
3. Page Based Pagination:
Page-based pagination is the most common type of pagination, where users navigate through pages using a page
query parameter. Laravel provides built-in support for this type.
$users = User::paginate(10); // 10 users per page
//generated sql
SELECT * FROM users LIMIT 10 OFFSET 0; -- Page 1
SELECT * FROM users LIMIT 10 OFFSET 10; -- Page 2
// example url
/users?page=2
// on frontend
@foreach ($users as $user)
<p>{{ $user->name }}</p>
@endforeach
{{ $users->links() }} <!-- Renders Bootstrap-style pagination -->
Custom way of doing page based pagiantion:
$page = request()->input('page', 1);
$limit = 10;
$offset = ($page - 1) * $limit;
$users = User::skip($offset)->take($limit)->get();
// generated sql
SELECT * FROM users LIMIT 10 OFFSET 10;
4. Keyset Based Pagination:
Keyset pagination is similar to cursor-based pagination but works with multiple keys (e.g., id
and created_at
).
$users = User::orderBy('created_at', 'asc')
->orderBy('id', 'asc')
->cursorPaginate(10);
// generated sql
SELECT * FROM users WHERE (created_at, id) > (?, ?) ORDER BY created_at, id LIMIT 10;
5. Time-Based Pagination:
Time-based pagination is a form of keyset pagination, where we use a timestamp (e.g., created_at
) as the cursor instead of an id
. This ensures efficient queries and avoids performance issues associated with OFFSET
-based pagination.
Laravel’s
cursorPaginate()
supports time-based pagination natively.
$users = User::orderBy('created_at', 'asc')->cursorPaginate(10);
//generated sql
SELECT * FROM users WHERE created_at > ? ORDER BY created_at ASC LIMIT 10;
//example url
/users?cursor=eyJjcmVhdGVkX2F0IjoiMjAyNS0wMy0yMiAwODowMDowMCJ9
//blade view
{{ $users->links() }}
//custom way of doing same
$limit = 10;
$cursor = request('cursor'); // Get timestamp from the request
$query = User::orderBy('created_at', 'asc');
if ($cursor) {
$query->where('created_at', '>', $cursor);
}
$users = $query->limit($limit)->get();
//generating next page cursor
$nextCursor = $users->last()?->created_at;
$nextPageUrl = $nextCursor ? url('/users?cursor=' . urlencode($nextCursor)) : null;
5. Hybrid Pagination (Offset + Cursor/Keyset):
Hybrid pagination combines offset-based pagination for initial pages and keyset/time-based pagination for deep pages.
$page = request()->input('page', 1);
$limit = 10;
$offsetLimit = 1000;
if ($page * $limit <= $offsetLimit) {
$users = User::orderBy('id')->offset(($page - 1) * $limit)->limit($limit)->get();
} else {
$cursor = request()->input('cursor');
$users = User::where('id', '>', $cursor)->orderBy('id')->limit($limit)->get();
}
🚀 Conclusion
Pagination is essential for web applications, but choosing the right strategy depends on your dataset size and requirements.
- Use Offset Pagination if you need simple navigation.
- Use Cursor/Keyset Pagination for large datasets & APIs.
- Use Time-Based Pagination for chronological ordering.
- Use Hybrid Pagination for the best performance and usability.
Which pagination method do you prefer in Laravel? Let me know in the comments! 🚀🔥