Offset vs Cursor vs Keyset Pagination: Best Practices for Scalable APIs

Table of contents
- 1. ๐ฅ Introduction: Why Pagination Matters
- 2. ๐งฎ Offset Pagination (LIMIT/OFFSET)
- 3. ๐งญ Cursor-Based Pagination (a.k.a. Seek Method)
- 4. ๐ Keyset Pagination (a refined Cursor Pagination)
- 5. ๐งช Real-World Code Comparisons
- 6. ๐ง Which One Should You Use?
- 7. ๐จ Common Pitfalls to Avoid
- 8. โ Conclusion: Pick the Right Tool for the Job
- ๐ฃ Call to Action:

Before we dig deep into the details. Letโs break down on what problem this article really addresses, what solution works best and what are the real world use cases โ
๐งต Problem:
GET /items
with 10,000 records? Brutal.๐ Solution: Explore pros/cons of offset, cursor-based, and keyset pagination.
๐ง Use cases: infinite scroll, large list APIs.
Letโs beginโฆ
1. ๐ฅ Introduction: Why Pagination Matters
Brief on modern APIs fetching massive datasets: products, users, posts, etc.
Without pagination:
Slow response times
High memory usage
Risk of app crashes
Pagination isnโt one-size-fits-all. Let's compare the three most popular strategies.
2. ๐งฎ Offset Pagination (LIMIT/OFFSET)
โ How it works:
SELECT * FROM products ORDER BY id LIMIT 10 OFFSET 30;
โ๏ธ Pros:
Simple to implement
Easy to understand for devs
Works well for small datasets
โ Cons:
Expensive on large datasets (DB still scans all skipped rows)
Risk of duplicate or missing data when records are inserted/deleted during pagination
Not ideal for infinite scroll or real-time apps
๐ ๏ธ When to use:
Admin dashboards
One-time exports
Non-realtime tables with moderate data
3. ๐งญ Cursor-Based Pagination (a.k.a. Seek Method)
โ How it works:
SELECT * FROM users WHERE id > 100 ORDER BY id ASC LIMIT 10;
- Instead of skipping rows, it uses a reference ("cursor") to fetch the next set.
โ๏ธ Pros:
Much faster on large datasets
Stable even if records are inserted or deleted
Ideal for real-time pagination or infinite scroll
โ Cons:
Harder to implement for multi-column sorts
Canโt jump to arbitrary page (e.g., page 500)
๐ ๏ธ When to use:
Public feeds (e.g. Twitter, Reddit)
Infinite scrolling
APIs with fast UX requirements
4. ๐ Keyset Pagination (a refined Cursor Pagination)
"Keyset" is the more academic name for cursor pagination when it involves compound primary keys or sort keys.
โ How it works:
SELECT * FROM posts WHERE (created_at, id) > (?, ?) ORDER BY created_at, id LIMIT 10;
- Uses multiple fields as cursors to avoid sorting conflicts
โ๏ธ Pros:
Most reliable and performant method
Eliminates page drift completely
Fully stable even during data changes
โ Cons:
Cannot jump to random page
Requires understanding of ordering logic
Slightly harder to paginate backward
๐ ๏ธ When to use:
Large datasets with dynamic insertions
Financial records, event logs, social media feeds
5. ๐งช Real-World Code Comparisons
REST API: Offset Example
GET /products?limit=10&offset=30
REST API: Cursor Example
GET /posts?after=eyJpZCI6MTAwMX0=
after
is a Base64 encoded cursor, like{ "id": 1001 }
MongoDB Example (Cursor style)
db.posts.find({
_id: {
$gt: ObjectId("...")
}
}).limit(10);
6. ๐ง Which One Should You Use?
Criteria | Offset | Cursor | Keyset |
Ease of use | โ โ โ | โ โ | โ |
Performance (large data) | โ | โ | โ โ โ |
Supports page jump | โ โ โ | โ | โ |
Consistent on changing data | โ | โ โ โ | โ โ โ |
Best for infinite scroll | โ | โ โ | โ โ โ |
7. ๐จ Common Pitfalls to Avoid
Sorting mismatch: Always match
ORDER BY
with your cursor condition.Stateless cursors: Donโt store pagination state server-side โ encode it in the cursor.
Unstable fields: Never paginate by non-unique or volatile fields like
name
.
8. โ Conclusion: Pick the Right Tool for the Job
Offset is easy, but fragile for large or live data.
Cursor is efficient, ideal for real-time apps.
Keyset is rock-solid for large-scale, high-integrity pagination needs.
Choose your pagination based on UX goals, dataset size, and data volatility.
๐ฃ Call to Action:
"Which pagination method do you use in your APIs today? Ever had to switch strategies mid-project? Share your experience below!"
Subscribe to my newsletter
Read articles from Faiz Ahmed Farooqui directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Faiz Ahmed Farooqui
Faiz Ahmed Farooqui
Principal Technical Consultant at GeekyAnts. Bootstrapping our own Data Centre services. I lead the development and management of innovative software products and frameworks at GeekyAnts, leveraging a wide range of technologies including OpenStack, Postgres, MySQL, GraphQL, Docker, Redis, API Gateway, Dapr, NodeJS, NextJS, and Laravel (PHP). With over 9 years of hands-on experience, I specialize in agile software development, CI/CD implementation, security, scaling, design, architecture, and cloud infrastructure. My expertise extends to Metal as a Service (MaaS), Unattended OS Installation, OpenStack Cloud, Data Centre Automation & Management, and proficiency in utilizing tools like OpenNebula, Firecracker, FirecrackerContainerD, Qemu, and OpenVSwitch. I guide and mentor a team of engineers, ensuring we meet our goals while fostering strong relationships with internal and external stakeholders. I contribute to various open-source projects on GitHub and share industry and technology insights on my blog at blog.faizahmed.in. I hold an Engineer's Degree in Computer Science and Engineering from Raj Kumar Goel Engineering College and have multiple relevant certifications showcased on my LinkedIn skill badges.