The Runtime Theory
hardApplicationDSA#backend#pagination#caching#distributed-systems

Design pagination for a feed that changes constantly

Tests whether you treat pagination as consistency management — keyset cursors, stable orderings, insert/delete behavior, and the cache-backed feed architecture.

The Runtime Theory Team2 min readasked at netflix · shopify · lyft · datadog

This question tests whether you understand pagination as consistency management, not just LIMIT/OFFSET. The interviewer wants you to realize the feed is moving while you read it, and to design a cursor that stays correct anyway.

The mental model: a page is a slice of an ordering, and the ordering must stay stable across requests.

Start with why offset pagination breaks. The feed is ordered by created_at DESC. The client requests page 1 (rows 0–9), then page 2 (rows 10–19). Between those requests five new posts are inserted, the rows shift down, and the client sees the tail of page 1 again on page 2 — duplicates — while a post inserted mid-feed silently misaligns everything. The database also pays: OFFSET 100000 scans and discards 100,000 rows, which is exactly what the pagination-scan trace shows as latency climbing the deeper you page.

Keyset (cursor) pagination fixes both. The client sends back an opaque cursor — the last item's ordering key — and the query becomes WHERE (created_at, id) < :cursor ORDER BY created_at DESC, id DESC LIMIT 10. New posts don't affect correctness: the cursor is a position in the ordering, and new items simply shift in ahead of it. And the database walks the index instead of scanning, so page 10,000 costs the same as page 1.

The subtleties are where the answer gets good. First, the ordering key must be unique and stable: created_at alone has ties, so pair it with the unique id and encode both in the cursor. Second, inserts and deletes are asymmetric: deletes can cause items to be skipped when resuming from a cursor, and inserts push new items into the top of the already-read region — neither is fatal, but you must decide whether the feed is insert-stable or delete-tolerant. Third, the cursor must be opaque to the client — base64-encode it — because exposing raw keys invites tampering and couples clients to internals.

At scale, the practical architecture: a Redis or in-memory cache holding the precomputed top-N feed (say 5,000 items), with pagination served from the cache via cursors into it — cache-hit pagination is near-free — while the keyset query against the database is the fallback for deep pages.

Tradeoffs and edge cases: cursor pagination can't jump to page 5 directly — no absolute position — which is fine for feeds but wrong for numbered admin tables, where you keep offset with an estimated count. The sharpest edge case: the item at the cursor is deleted between requests — the cursor must reference the ordering key, not the item, so the query still runs. And the cursor key's uniqueness is non-negotiable: a non-unique key silently drops or duplicates items.

This answer walks

Follow-ups they'll push on

  1. 01Why does OFFSET pagination get slower as you page deeper?
  2. 02What happens when the item at the cursor is deleted between requests?
  3. 03When would you keep offset pagination instead?
  4. 04Why must the cursor key be unique?

More interviews in this topic

One dispatch a week

The trace behind each question, the tradeoff that explains it, and one technical dispatch per week — no noise.

One technical dispatch per week. No noise.