Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time
November 25, 2020 16:04
November 19, 2020 15:53
December 10, 2021 18:11
December 10, 2021 17:46
November 19, 2020 15:53
November 19, 2020 15:19
November 19, 2020 16:41
November 25, 2020 15:47
November 19, 2020 15:54
November 19, 2020 15:54
January 2, 2022 21:08


PkgGoDev Test

An efficient go data cursor-based paginator.

  • Plug and play
  • Easy to use
  • Fully customizable
go get


A lot of articles on the internet summarize very well the benefits of cursor-based pagination, but here are the highlights:

  • It scales: Unlike OFFSET/LIMIT-based pagination doesn't scale well for large datasets
  • Suitable for real-time data: having a fixed point in the flow of data prevents duplicates/missing entries

It does have an issue, it is hard to implement, that's why go-paginate exists :)


  • gorm:

    • Supports multiple columns with different orderings directions (ex: ORDER BY id ASC, name DESC)
  • Implement your own: See driver.Driver and base.Driver

Can't find what you are looking for? Open an issue!


With gorm

Errors omitted for brevity

Create the paginator, defining the criteria (columns and ordering):

pg := paginator.New(paginator.Options{
    Driver: gorm.New(gorm.Options{
        Columns: []gorm.Column{
                Name: "created_at",

Create the cursor instance, most likely from the request (in the initial request, the cursor is an empty string):

c, err := pg.Cursor("<cursor from client>", cursor.After, 2)

Create a transaction with appropriate filtering etc and request the pagination info:

tx := db.Model(&User{}).Where(...)
page, err := pg.Paginate(c, tx)

// That should be sent back to the client along with the data

Retrieve the underlying data for the page:

var users []User
err := page.Query(&users)

A full working example can be found in _examples/gorm.

Custom cursor

By default, the cursor will be marshalled through msgpack for size concerns, and base64 for portability. One can choose to do differently (for example encrypting them...), see the implementation of cursor.MsgPack and cursor.Base64.

pg := paginator.New(paginator.Options{
    CursorMarshaller: cursor.Chain(cursor.MsgPack(), cursor.Base64(base64.StdEncoding))


TAG=v0.0.1 make tag