reliability

Pagination

Return list endpoints in chunks so clients can scroll without overwhelming the server or the network.

A list endpoint that returns every matching row works fine in development with a few hundred records and falls over in production with millions — slow queries, huge payloads, and exhausted memory on both ends. Pagination breaks a large result into manageable pages so clients fetch only what they need, and the choice of pagination strategy has real consequences for correctness and performance at scale.

Offset = "give me page 50 of the book." Cursor = "give me the page after the one I just read."

Key Concepts

1
The two main approaches trade simplicity against robustness. Offset pagination (?page=3&size=20, translating to SQL LIMIT 20 OFFSET 40) is intuitive and allows jumping to an arbitrary page, but it degrades on large datasets because the database must still scan and discard all the skipped rows, and it is unstable under concurrent writes — if a row is inserted while a user pages, items shift and they see a duplicate or skip one. Cursor (or keyset) pagination instead returns an opaque cursor pointing at the last item seen (typically encoding a sort key like created_at plus id), and the next page asks for items "after" that cursor with a WHERE clause the index can seek directly. This stays fast no matter how deep you page and is stable against inserts, at the cost of not supporting random page jumps. Either way, the response should include the page of data plus metadata — a next cursor or total count and links — so the client knows how to continue.
?page=3&size=20LIMIT 20 OFFSET 40created_atWHERE
2
The interview-relevant guidance is to default to cursor-based pagination for large, append-heavy, or infinite-scroll datasets and reserve offset pagination for small or admin-style lists where page jumping matters and the data is modest. It is also worth mentioning enforcing a maximum page size so a client cannot request a million rows at once, and being deliberate about whether to compute an expensive total count, which on big tables can be slower than fetching the page itself.