Programming · free software · the open webSubscribe via RSS

How Should Large Data Responses Be Paginated?

From the earlier reference collection. Read the current software blog.

Reliable pagination depends on a deterministic order and a continuation rule that remains valid as clients request later pages.

Why split a response

A large response can take longer to transfer, consume more memory, and be harder for a client to recover if a request fails. Pagination divides it into manageable pieces. But page boundaries are part of the data contract: clients need to know how to ask for the next slice and whether the slices form a complete, non-overlapping sequence.

A response might return 100 records and a continuation token. The token should let the service resume after the last returned record. It should not merely mean “go to page 2” if insertions or deletions can change what page 2 contains.

Use a stable ordering

The service must define a repeatable sort order. Sorting by a non-unique field alone is insufficient. If several records share the same timestamp, ordering only by timestamp leaves their relative positions undefined. Add a unique tie-breaker, such as an immutable record ID, and order by the pair.

For example, sort by (updated_at, record_id). If the last item on a page has timestamp 14:05 and ID 812, the next request can continue after that pair. Without the tie-breaker, equal timestamps may cause one record to appear twice or another to be skipped.

Design the continuation contract

An opaque continuation token can encode the position and any query context required to continue. Clients should treat it as a value to pass back, not inspect or construct. The service should bind it to relevant filters and sort order so that a token from one query cannot silently continue a different query.

Data can change between page requests. Decide whether pagination represents a snapshot or a moving view. A snapshot gives the client a consistent point-in-time result, if the system supports that. A moving view is simpler but may reflect later changes; document the tradeoff and make the ordering robust enough to minimize surprises.

Check the sequence

Test with records that share sort values, records inserted during retrieval, and a final page with fewer than the requested number. Collect every page and verify that each expected record appears exactly once. Also test that an expired or malformed token produces a clear error rather than an unrelated page.

A good response tells clients whether more data remains, provides the continuation token when appropriate, and defines how to finish. Clear pagination behavior makes large exports predictable and helps clients resume work without guessing at offsets or silently losing records.

Suggest a correction · All posts