Pagination
Pagination returns a collection in slices. There are two common strategies, and the right choice depends on how big and how dynamic your data is.
Offset pagination
Section titled “Offset pagination”The client asks for a page by position: ?page=3&limit=20 (or ?offset=40&limit=20). Simple, allows jumping to any page, and shows total counts easily.
GET /articles?page=2&limit=20Its weakness: deep offsets are slow (the database must skip all preceding rows), and inserts shift the window — if a row is added while you page, you can see duplicates or skip items.
Cursor pagination
Section titled “Cursor pagination”The client passes an opaque cursor marking where the last page ended: ?limit=20&cursor=eyJpZCI6MTQwfQ. The server returns the next slice plus the cursor for the page after.
flowchart LR A[GET /articles?limit=20] --> B[20 items + nextCursor] B --> C[GET /articles?limit=20&cursor=...] C --> D[next 20 + nextCursor]
Cursors are stable under inserts and fast at any depth, but you cannot jump to an arbitrary page and exact totals are harder. They are the better default for large or frequently-changing collections (feeds, logs, search).
Slicing and the envelope
Section titled “Slicing and the envelope”A page should be wrapped in an envelope with data plus paging metadata and links: