Offset or Cursor? Choosing the Right Pagination for Your API Needs 🎯

Digvijay Bhakuni
4 min read2 days ago

--

Welcome to the world of API Pagination! If you’re building APIs or working with them, you’ve probably heard the term “pagination.” But what is it? Why do we need it? And what types are there? Let’s dive in and make sense of it all, step by step! 🐾

Photo by Ante Hamersmit on Unsplash

🌀 What is API Pagination?

When your API is serving lots of data (think hundreds, thousands, or millions of records), sending everything at once isn’t practical. Imagine trying to stream all the movies on Netflix in one go — your app (and your users!) would crash. 😅

Pagination solves this by breaking the data into smaller, manageable chunks. Instead of fetching all the data at once, we fetch a specific slice at a time. This is great for:

  • Improving performance (less data = faster response).
  • Reducing memory usage on both client and server.
  • Allowing navigation (e.g., “Load More” or “Next Page” buttons).

📜 Types of API Pagination

Offset-Based Pagination

This is the classic way of paginating data. It uses an offset (where to start) and a limit (how many records to fetch).

🧮 Variants:

Page-Size Based: You specify a page number and the number of items per page. For example:

GET /items?page=2&page_size=5

This fetches the second page with 5 items per page.

Offset-Limit Based: You specify an offset (starting point) and a limit (number of items to fetch). For example:

GET /items?offset=10&limit=5

This fetches 5 items starting from the 10th item.

🎯 When to Use:

  • Simple datasets where items don’t change frequently (e.g., a catalog of products).
  • User interfaces with straightforward navigation like “Next” and “Previous” buttons.

✅ Pros:

  • Easy to implement.
  • Works well with SQL databases (e.g., LIMIT and OFFSET queries).

❌ Cons:

  • Can get slow for large datasets, as skipping many rows can be expensive.
  • Prone to data inconsistency if items are added/removed while paginating (e.g., you might skip or duplicate records).

Cursor-Based Pagination

Cursor-based pagination is a modern, efficient approach. Instead of using a number to indicate the starting point, it uses a cursor — a unique identifier for where the last batch ended.

🧮 Variants:

Key-Based: Uses a unique key (like an ID) to fetch the next set of records. For example:

GET /items?cursor=last_seen_id

This fetches items after the given last_seen_id.

Time-Based: Uses timestamps to fetch records. For example:

GET /items?cursor=2023-11-20T10:30:00Z

This fetches items created after the specified time.

🎯 When to Use:

  • Large datasets that need high performance.
  • Scenarios where data frequently changes (e.g., real-time feeds like social media).
  • When you need consistent ordering (e.g., sorting by creation time or ID).

✅ Pros:

  • More efficient for large datasets (doesn’t need to skip rows).
  • Avoids data inconsistencies (e.g., no skipped or duplicated records).
  • Works great with infinite scrolling UI.

❌ Cons:

  • More complex to implement (you need to handle cursors carefully).
  • Requires strict ordering of data (e.g., sorting by ID or timestamp).

🎉 Which is Better?

It depends on your use case! Here’s a quick summary:

| Criteria              | Offset-Based           | Cursor-Based             |
|-----------------------|------------------------|--------------------------|
| Data Volume | Small to medium | Large datasets |
| Data Changes Often? | Not ideal | Excellent |
| Implementation Ease | Simple | Slightly complex |
| Performance | Slower for large data | Faster for large data |
| UI Type | Paged navigation | Infinite scrolling |

🔍 Real-Life Examples

📝 Offset-Based Pagination

Imagine you’re building an e-commerce API to list products:

GET /products?page=3&page_size=10
{
"page": 3,
"page_size": 10,
"data": [
{"id": 21, "name": "Product A"},
{"id": 22, "name": "Product B"},
// ...
]
}

🕒 Cursor-Based Pagination (Key-Based)

You’re building a social media feed where posts are ordered by ID:

GET /posts?cursor=12345
{
"cursor": "12350",
"data": [
{"id": 12346, "content": "Hello World!"},
{"id": 12347, "content": "New Post!"},
// ...
]
}

⏰ Cursor-Based Pagination (Time-Based)

You’re building a news feed where articles are fetched by timestamp:

GET /articles?cursor=2024-11-20T12:00:00Z
{
"cursor": "2024-11-21T10:00:00Z",
"data": [
{"id": 101, "title": "Breaking News"},
{"id": 102, "title": "Tech Update"},
// ...
]
}

🤔 Final Thoughts

Pagination is your API’s best friend when it comes to handling large datasets. Here’s the takeaway:

  • Use Offset-Based for simple, static data with predictable sizes.
  • Use Cursor-Based for high-performance, real-time, or large datasets.

Choose the approach that best fits your app’s needs and scale confidently! 🎉 If you have any questions, drop them below 👇 — I’m here to help! 😄

--

--

No responses yet