Cursor Pagination

A pagination strategy where the client provides a pointer (cursor) to a specific record in the dataset, and the server returns the next set of results following that record.

Cheat Sheet

Prime Use Case

Essential for infinite scroll UIs, high-frequency data feeds, and large-scale datasets where performance and consistency are paramount.

Critical Tradeoffs

  • Eliminates item skipping/duplication during data mutations
  • O(1) or O(log N) performance regardless of depth
  • Prevents 'Jump to Page X' functionality
  • Requires unique, deterministic sort keys

Killer Senior Insight

Cursor pagination shifts the pagination state from the 'index' of the result set to the 'identity' of the data itself, making it the only viable solution for distributed systems where the underlying dataset is a moving target.

Recognition

Common Interview Phrases

Design a news feed like Facebook or Twitter
How do we handle items being added while the user is scrolling?
The database query is timing out for users on page 500
We need to support bi-directional infinite scrolling

Common Scenarios

  • Social media activity feeds
  • Real-time chat message history
  • Audit logs and event streams
  • E-commerce product listings with infinite scroll

Anti-patterns to Avoid

  • Admin dashboards requiring specific page navigation
  • SEO-driven content where 'Page 5' must be a shareable, static URL
  • Small, static datasets where Offset pagination is simpler to implement

The Problem

The Fundamental Issue

The 'Offset Drift' problem, where users see duplicate items or skip items entirely when records are inserted or deleted while they are paginating.

What breaks without it

User experience suffers from 'stuttering' feeds (seeing the same post twice)

Database performance degrades linearly (O(N)) as users navigate deeper into the results

Inconsistent data views across different client sessions

Why alternatives fail

Offset pagination requires the database to scan and discard all previous rows before returning the requested window

Offset is stateless; it doesn't know if the item at index 10 is the same item that was at index 10 a second ago

Mental Model

The Intuition

Think of a bookmark in a physical book. Offset pagination is like saying 'Open to page 50'—if someone rips out page 10, the content of 'page 50' changes. Cursor pagination is like saying 'Start reading after the sentence that ends with the word Apple'—no matter how many pages are added or removed before it, you always know exactly where to resume.

Key Mechanics

1

Unique, ordered identifier (e.g., UUID, Snowflake ID, or Timestamp + ID)

2

Opaque cursor token (usually Base64 encoded) sent to the client

3

API response includes 'next_cursor' and 'has_next_page' metadata

4

SQL 'WHERE' clause filtering on the cursor value instead of 'OFFSET' skipping

Framework

When it's the best choice

  • Infinite scrolling or 'Load More' patterns
  • Mobile applications with 'Pull to Refresh' capabilities
  • High-concurrency environments with frequent writes

When to avoid

  • When users need to jump to the middle or end of a list immediately
  • When the UI must display the total number of pages
  • When the data cannot be sorted by a unique, immutable column

Fast Heuristics

If 'Jump to Page' is a hard requirement
Use Offset
If 'Data Consistency' is a hard requirement
Use Cursor
If 'Deep Pagination Performance' is a concern
Use Cursor

Tradeoffs

+

Strengths

  • Stable results: items don't shift when new data is inserted
  • High performance: utilizes database indexes efficiently without scanning skipped rows
  • Scalability: works well with distributed databases and sharding
  • Reduced server load: avoids expensive 'COUNT(*)' queries for every request

Weaknesses

  • No random access: users cannot skip to arbitrary positions
  • Implementation complexity: requires careful selection of sort keys and tie-breakers
  • Harder to debug: opaque cursors are not human-readable
  • Sorting limitations: the cursor must be tightly coupled to the sort order

Alternatives

Offset Pagination
Alternative

When it wins

Small datasets or UIs requiring explicit page numbers and 'Jump to Page' functionality.

Key Difference

Uses a numeric skip count (OFFSET) rather than a record-specific pointer.

Keyset Pagination
Alternative

When it wins

When you want the performance of cursors but want to keep the API parameters transparent and readable.

Key Difference

Uses raw field values (e.g., ?since=2023-01-01) directly in the URL instead of an opaque Base64 token.

Execution

Must-hit talking points

  • Mention the Relay Connection Specification as the industry standard for cursor-based APIs
  • Explain the importance of 'Opaque Cursors' to prevent clients from depending on internal DB structures
  • Discuss 'Tie-breaking': using a secondary unique column (like ID) if the primary sort column (like Timestamp) is not unique
  • Address bi-directional pagination using 'before' and 'after' cursors

Anticipate follow-ups

  • Q:How would you handle a cursor for a record that was just deleted?
  • Q:How do you implement 'Previous Page' logic efficiently?
  • Q:What are the security implications of exposing internal IDs in cursors?
  • Q:How does this interact with client-side caching libraries like Apollo or React Query?

Red Flags

Using a non-unique column as the sole cursor.

Why it fails: If multiple records share the same value (e.g., same timestamp), the pagination will skip records or enter an infinite loop.

Exposing raw database IDs in the cursor string.

Why it fails: It leaks internal implementation details and makes it difficult to change the underlying data store or sorting logic without breaking clients.

Calculating 'Total Count' on every cursor request.

Why it fails: The performance benefit of cursors is negated if the database still has to perform a full table scan to count all records.