CalcSnippets Search
APIs 3 min read

API Pagination Patterns: Offset, Cursor, and Keyset

Compare API pagination patterns including offset, cursor, and keyset pagination for performance, consistency, developer experience, and large datasets.

Pagination is part of the API contract

APIs paginate because lists grow. Users may have thousands of orders, events, messages, search results, invoices, or audit records. Returning everything at once is slow, expensive, and unreliable. Pagination gives clients a way to request data in manageable chunks while keeping the API responsive.

The pattern matters because it affects performance, consistency, caching, and developer experience. A small internal list can use a simple approach. A high-volume public API with changing data needs more careful design.

Offset pagination is simple but can become slow

Offset pagination uses parameters such as limit and offset, or page and page size. It is easy to understand and works well for small or moderately sized datasets. It also supports jumping to a specific page, which can be useful for some admin interfaces.

The weakness appears with deep pages and frequently changing data. A database may need to scan past many rows before returning the next page. If new records are inserted while the user paginates, items can appear twice or be skipped. For large feeds, logs, and timelines, offset can become both slow and inconsistent.

  • Use offset pagination for small, stable lists and simple admin pages.
  • Use cursor pagination for changing lists and public APIs.
  • Use keyset pagination when performance and stable ordering matter.
  • Document sort order, limits, and whether cursors expire.

Cursor pagination is better for moving datasets

Cursor pagination returns a token that represents the next position in the list. The client does not need to know the database offset. The server can encode sorting information, filters, and position into the cursor. This is useful for activity feeds, messages, events, and APIs where data changes while clients are paging.

Cursors should be opaque. Clients should treat them as tokens, not parseable state. This gives the API freedom to change internal implementation later. Include clear fields such as next_cursor, has_more, and stable page size rules so client code stays predictable.

Keyset pagination uses the last seen value

Keyset pagination uses a stable ordered column, such as creation time plus ID, to request records after the last item seen. It can be very efficient because the database can use an index to continue from a known key. It works best when the sort order is stable and indexed.

The tradeoff is that arbitrary page jumps are harder. Many user experiences do not need page 47; they need next, previous, or load more. For those cases, keyset pagination is often a better performance choice.

Pagination should be tested with real data

Test empty lists, first page, last page, deleted records, new records during paging, changed filters, invalid cursors, and large datasets. Pagination bugs are frustrating because they make users lose trust in the completeness of results. A good API makes paging boring: stable order, clear limits, safe tokens, and performance that does not collapse as the product grows.

Keep reading

Related guides