Dec 10, 2025 • 5 mins read
Pagination looks simple until your application starts to grow.
When I first built feeds and lists, I used offset-based pagination without much thought.
It worked perfectly in development, felt intuitive, and was easy to implement.
But once you start thinking in terms of real users, real traffic, and constantly changing data, offset pagination begins to show serious cracks.
That’s where cursor pagination becomes not just an optimization but a necessity.
Offset pagination usually looks like this:
SELECT * FROM posts
ORDER BY created_at DESC
LIMIT 10 OFFSET 20;
At first glance, it seems harmless. But offset-based pagination has three major problems at scale.
Performance Degrades as Data Grows The database must scan and skip rows before returning results. As the offset increases, queries become slower and more expensive. Fetching page 50 is significantly more costly than page 1.
Inconsistent Results on Dynamic Data In real applications, data changes constantly. New records get inserted. Old ones get deleted.
With offset pagination:
This breaks the user experience, especially in feeds and timelines.
Pagination Becomes Unreliable Offset pagination assumes data is static between requests. In reality, that assumption is almost never true. This is why large-scale systems rarely rely on offset pagination for feeds.
Cursor pagination works by anchoring the next page to a specific record, not a number. Instead of saying:
“Give me page 3”
You say:
“Give me the next 10 items after this record”
That “record” is the cursor. A cursor is usually:
createdAt)id)A typical cursor-based query looks like this:
SELECT *
FROM posts
WHERE created_at < :cursor
ORDER BY created_at DESC
LIMIT 10;
Here’s what’s happening:
createdAt of the last itemThis guarantees:
Timestamps work well as cursors because:
However, timestamps alone can clash if two records share the same time. That’s why many systems use:
createdAt, id) togetheridThe goal is deterministic ordering.
In an API, cursor pagination usually looks like this:
GET /feed?limit=10&cursor=2025-12-10T12:30:00Z
And the response includes:
nextCursor valueThe frontend doesn’t care how pagination works internally. It simply passes the cursor back to fetch the next page.
Cursor pagination:
This is why platforms like social feeds, timelines, and activity logs rely on it.
Use offset pagination when:
Use cursor pagination when:
If the data can change between requests, offset pagination is already a bug waiting to happen.
Cursor pagination isn’t just a “better pagination technique.” It’s a shift in how you think about data access.
Instead of slicing data by position, you move through it by state. Once you understand cursor pagination, it changes how you design scalable systems.
If you’re building feeds, timelines, or infinite scrolls, cursor pagination isn’t optional. It’s foundational.