Skip to content
Cursor vs Offset Pagination: Why It Matters at Scale 3 min

Cursor vs Offset Pagination: Why It Matters at Scale

SD
ScaleDojo
May 11, 2026
3 min read644 words
cursor_vs_offset.png

The Problem

Your users table has 5 million records. A client requests GET /users. You can't return all 5 million records in one response, that would be gigabytes of data, take minutes to load, and crash mobile clients. Pagination solves this: return results in pages of 20 to 100 records, but the cursor vs offset pagination decision you make here determines whether that endpoint stays fast as the table grows.

But how you implement pagination has massive performance implications. The wrong choice turns a 5ms query into a 5 second query, and your database administrator sends you angry messages at 3am.

ChatGPT Image Jul 19, 2026, 02_14_43 PM.png

Architecture overview

Offset Pagination: Simple but Dangerous

The intuitive approach: GET /users?page=3&limit=20 translates to skip the first 40 records, return the next 20.

ChatGPT Image Jul 16, 2026, 12_33_35 AM.png

The deeper you paginate, the slower it gets. It's O(N), where N is the offset value.

There's a second problem: if a new record is inserted while you're paginating, you might see a record twice (on page N and page N+1) or skip one entirely. The data is shifting under your feet while you read it.

Cursor Pagination: Fast at Any Depth

Instead of saying "skip N records," cursor pagination says "give me records after this specific point." The cursor is typically the ID or timestamp of the last item you received, and it's the backbone of most modern API pagination best practices.

ChatGPT Image Jul 16, 2026, 12_37_07 AM.png

Whether you're on page 1 or page 50,000, the database uses the index to jump straight to the starting point. No scanning, no skipping.

Visual Comparison

ChatGPT Image Jul 16, 2026, 12_42_48 AM.png

The API Response Format

A good cursor-based response for pagination in a REST API looks like this:

ChatGPT Image Jul 17, 2026, 04_23_33 PM.png

Sorting by Non-Unique Columns

What if you need to sort by created_at instead of id? Multiple users can share the same created_at, so a plain cursor on that column alone isn't safe. Use a composite cursor instead:

ChatGPT Image Jul 19, 2026, 02_11_57 PM.png

When to Use Which

This is the core of the cursor vs offset pagination decision, and it usually comes down to how deep users will paginate and how fast your data grows:

Criteria

Offset

Cursor

Performance at deep pages

O(N), gets slower

O(1), always fast

Jump to page X

Yes (page=47)

No, sequential only

Data consistency during inserts

Duplicates/skips possible

Stable, no shifting

Total count

Easy (COUNT(*))

Expensive or separate query

Best for

Admin panels, small datasets (<100K rows)

Public APIs, infinite scroll, mobile apps, any growing dataset

Numbers That Matter

  • Offset of 1M on a table of 10M rows: roughly 500ms to 5s depending on row size and indexes

  • Cursor pagination on the same table at any position: a consistent 1 to 5ms

  • Twitter's timeline API uses cursor pagination, serving billions of timeline requests per day

  • Stripe's list APIs all use cursor pagination, with auto-pagination built into their client libraries

  • GitHub's GraphQL API uses cursor-based connections exclusively

If you're also thinking about how to keep those paginated reads fast under load, it's worth pairing this with a solid caching strategy, since cached first pages can absorb a huge share of traffic before the database ever sees a query.

Interview Tip

When an interviewer asks about pagination, immediately say: "I would use cursor-based pagination for any public-facing API or dataset that will grow, because offset pagination is O(N) at deep pages while cursor is O(1). The cursor would be a Base64-encoded composite of the sort key and a unique tiebreaker like the row ID." Then add: "For admin dashboards where users need to jump to page 47, offset is acceptable if the dataset is small." This shows you understand both approaches and their trade-offs.

Pagination is a small piece of a bigger picture, and it tends to come up alongside broader API design questions in interviews. If you want to see how this fits into the rest of the design, the low-level design fundamentals guide and the piece on API gateways and BFF patterns are good next reads.

Key Takeaway

Offset pagination is O(N), it degrades the deeper you go. Cursor pagination is O(1), consistently fast regardless of position. For any public API or dataset that might grow, default to cursor pagination. Use composite cursors (sort key plus ID) when sorting by non-unique columns.

Enjoyed this article?

Share it with your network to help others level up their system design skills.

Discussion0

Join the Discussion

Sign in to leave comments, reply to others, or like insights.

Sign In to ScaleDojo

No comments yet. Be the first to start the thread!

Related Articles

Enjoyed this content?

Your support keeps us creating free resources

We put a lot of hours into researching and writing these guides. If it helped you, consider buying us a coffee. Every bit goes toward keeping ScaleDojo's content free and growing.

$

One-time payment via Stripe. ScaleDojo account required.

ScaleDojo Logo
Initializing ScaleDojo