Use Cursor Pagination

This guide shows you how to implement cursor-based pagination for efficient navigation through large datasets.

Why Cursor Pagination?

Cursor pagination is better than offset pagination for:

  • Large datasets (offset becomes slow)

  • Real-time data (new items don't shift pages)

  • Infinite scroll interfaces

  • API pagination

Basic Cursor Pagination

Use the ID as a cursor:

def fetch_posts(after : Int64?, limit : Int32 = 20)
  query = Post.published.order(id: :desc).limit(limit + 1)

  if after
    query = query.where { id < after }
  end

  items = query.all

  # Check if there are more items
  has_more = items.size > limit
  items = items.first(limit) if has_more

  {
    items: items,
    next_cursor: has_more ? items.last?.try(&.id) : nil,
    has_more: has_more
  }
end

Usage

Bidirectional Cursors

Support forward and backward navigation:

Timestamp-Based Cursor

For chronologically ordered data:

Compound Cursor

When ordering by non-unique column:

API Response Format

Encode/Decode Cursors

For opaque cursors:

Verify Cursor Pagination Works

Last updated

Was this helpful?