Lesson 5 of 17
24. APIs and Idempotency

24.4 How does pagination work (offset vs cursor)?

3 min read+10 XP

At the machine: The screen shows items 1-10. You press ▶ for the next 10. If the shop restocks while you're scrolling, the list can shift under you.

In the system: Lists (orders, books, reviews) are too long to return in one response, so APIs return pages. Two ways:

Offset pagination: GET /orders?offset=20&limit=10 → "skip 20, give me 10".

  • Simple, and you can jump to page 7.
  • Shifting data: if a new order arrives at the top between page 1 and page 2, everything moves down one, so the last item of page 1 appears again on page 2 (deletes make items vanish instead). In the chapter's code, order 91 is shown twice.
  • Slow deep pages: OFFSET 100000 makes the database read and throw away 100,000 rows.

Cursor (keyset) pagination: GET /orders?after=91&limit=10 → "give me 10 after the last one I saw".

  • The server turns it into WHERE id < 91 ORDER BY id DESC LIMIT 10, which uses the index, so page 1,000 is as fast as page 1.
  • Stable: new or deleted rows don't cause repeats or gaps. In the chapter's code, page 2 starts at 90 even though order 101 arrived.
  • Can't jump to "page 7"; the cursor is usually an opaque string (encoded sort key and ID) so clients don't build it themselves.

offset pagination shows order 91 twice after a new order arrives; cursor pagination doesn't.

Figure: "skip N" breaks when the list changes; "after this one" doesn't.

Use cursors for feeds, timelines, order histories and any large or changing list; offsets are fine for small, stable lists or admin screens that need page numbers. Always cap the page size.

Memory code: "Don't say 'skip 20'; say 'after this one'."