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

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?

CriteriaOffsetCursorKeyset
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!"

0
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.