Alexander Claes
← Writing

When cursor pagination is the better choice

Cursors can make growing lists easier to browse, but they bring trade-offs in navigation and consistency.

Alexander ClaesAlexander Claes2 min read
Engineering
Colourful tickets line up around a dark cursor marker while a yellow ticket jumps over it.
The cursor marks where to continue, even as the surrounding list changes.

Numbered pages work well for many lists. You request page two, skip the first set of results and receive the next. But for a growing feed or a long list with “Load more”, a cursor can be a better fit.

The difference is how the next request remembers where to continue.

Continuing from a position

Imagine projects ordered by their latest update: A, B, C, D, E, F. The first page shows A, B and C.

Offset pagination loads the next page by skipping three projects. If D gets updated and moves to the top, the order becomes D, A, B, C, E, F. Skipping three now returns C again.

A cursor instead saves C’s position, using its update time and a unique ID to break ties. The next request continues after those saved values. Records appearing above that boundary do not cause C to repeat.

With a suitable database index, the query can also seek to that position instead of processing all the earlier rows. That becomes useful as someone browses deeper into a large list.

What you give up

Cursors suit browsing in sequence. Jumping straight to page 12 is less straightforward because you normally need a cursor from an earlier request. For a small table where numbered pages help people navigate, offsets may be simpler.

Both approaches can miss or repeat records when the values used for sorting change between requests. In the example, D moves into the part you already passed. A cursor avoids repeating C because of the shifted offset, but you still need to refresh to see D. It makes continuing more predictable without preserving a fixed version of the list.

Choosing the order matters

Sorting by a fixed created_at value and an ID prevents existing records from changing position. That is often a good choice for a chronological feed.

But a recently updated project list needs old projects to move up when work resumes. Creation order would make pagination steadier while showing the wrong order for that purpose.

For a live list, refreshing may be enough to pick up changes. An exact export needs a fixed set of results across requests.

Choose a cursor when sequential browsing and efficient access to later results matter. Then decide which changes the interface can tolerate while someone moves through the list.