advanced 2 min answer

A discussion platform paginates a feed whose ranking changes continuously as votes arrive. Offset pagination shows duplicates and gaps. What are the options, and what does each cost the product?

paginationcursorsrankingfeedsreddittrade-off
Show the full answer Hide the answer

Why this is harder than ordinary pagination

Cursor pagination solves instability from insertions by encoding a position in a stable sort order. But here the sort order itself is unstable: an item's rank changes as votes arrive, so an item on page 1 can move to page 3 while the user is reading, and an item from page 3 can move to page 1.

There is no cursor into a continuously reordering list that guarantees each item is seen exactly once. This is not an implementation problem; it is a property of the data.

The options

1. Snapshot the ranking per session. Compute the ordering once when the user starts browsing, cache it, and paginate through the frozen list. Each item is seen exactly once and pagination is trivially correct.

Cost: the feed is stale for the session's duration. A user browsing for ten minutes sees ten-minute-old ranking, which for a fast-moving discussion feed is a real product regression — the freshness is much of the value.

2. Cursor on a stable secondary key. Paginate by a monotonic key — creation time, or a score frozen at insertion — and apply live ranking only within the page. Correct pagination, approximate ranking.

Cost: the ordering the user sees is not the true current ranking, and the discrepancy grows with depth.

3. Accept imperfection and deduplicate client-side. Continue with rank-based cursors, and have the client track seen identifiers and drop repeats.

Cost: gaps remain invisible — the client cannot know about an item it never received. Cheap, and the usual pragmatic answer for feeds where completeness is not promised.

4. Seen-set on the server. Track what the user has been shown and exclude it from subsequent pages. Correct, and the most expensive: per-user state that grows with browsing and must be stored, expired and consulted on every page.

How to choose

By what the product actually promises.

  • A ranked discovery feed promises interesting content, not exhaustive enumeration. Option 3 or 2 is right, and the small imperfection is invisible.
  • A user's own content, a moderation queue, or a notification list promises completeness. These need option 1 or 4, and they are usually small enough that snapshotting is cheap.
  • An API for third-party developers doing a full sync needs a different mechanism entirely: a stable ordering by immutable key, or an event stream. Never expose a ranked feed as the bulk-access path, because integrators will use it for that and their data will be silently incomplete.

The lesson

Pagination correctness is a product decision before it is a technical one. The question is not "how do we paginate a changing list" — which has no perfect answer — but "what does the user believe they are seeing, and which guarantee does that require". Different surfaces in the same product legitimately warrant different answers.