Docs
General
Types
Codegen
Extensions
>Errors
>Guides
Editor integration
Concepts
Integrations
Federation
Operations
Pagination
Whenever we deal with lists in GraphQL, we usually need to limit the number of items returned. Surely, we don't want to send massive lists of items that take a considerable toll on the server! The goal of this guide is to help you get going fast with pagination!
Pagination at a Glance
Let us take a look at some of the common ways pagination can be implemented today!
Offset-Based Pagination
This type of pagination is widely used, and it is similar to the syntax we use when looking up database records.
Here, the client specifies:
limit
: The number of items to be obtained at a time, andoffset
: The number of items to be skipped from the beginning.
Implementing offset-based pagination with an SQL database is straightforward.
We use the limit
and offset
values given to query for the items.
Offset-based pagination also provides us the ability to skip ahead to any offset, without first needing to get all the items before it.
Let us understand offset-based pagination better, with an example. Let us assume that we want to request a list of users, two at a time, from a server.
We start by sending a request to the server, with the desired limit
and offset
values.
{ "limit": 2, "offset": 0}
We are not sending GraphQL requests here, don't worry about the request format for now! We are looking into pagination conceptually. We'll implement pagination in GraphQL later!
The response from the server would be:
{ "users": [ { "id": 1, "name": "Norman Osborn", "occupation": "Founder, Oscorp Industries", "age": 42 }, { "id": 2, "name": "Peter Parker", "occupation": "Freelance Photographer, The Daily Bugle", "age": 20 } ]}
To get the next two users, we can send another request, incrementing offset
by the value of limit
.
{ "limit": 2, "offset": 2}
We can repeat this process, incrementing offset
by the value of limit
, until we get an empty result.
Pagination Metadata
In the example above, the result contained no metadata, only the items at the requested offset and limit.
It may be useful to add metadata to the result. For example, the metadata may specify how many items there are in total, so that the client knows what the greatest offset value can be.
{ "users": [ ...
] "metadata": { "count": 25 }}
Using page_number Instead of offset
Instead of using limit
and offset
as the pagination parameters, it may be more useful to use page_number
and page_size
.
In such a case, the metadata in the result can be pages_count
. The client starts the pagination at page_number
1,
incrementing by 1 each time to get the next page, and ending when page_size
is reached.
This approach may be more in line with what a typical client actually needs when paginating.
Limitations of Offset-Based Pagination
Offset-based pagination has a few limitations:
- It is not suitable for large datasets, because we need to access offset + limit number of items from the dataset, before discarding the offset and only returning the requested items.
- It doesn't work well in environments where records are frequently added or removed, because in such cases, the page window becomes inconsistent and unreliable. This may result in duplicate items or skipped items across pages.
However, it provides a quick way to get started, and works well with small-medium datasets. When your dataset scales, you will need a reliable and consistent way to handle pagination.
Cursor based pagination
Cursor based pagination, also known as keyset pagination, works by returning a pointer to a specific item in the dataset. On subsequent requests, the server returns results after the given pointer. This method addresses the drawbacks of using offset pagination, but does so by making certain trade offs:
- The cursor must be based on a unique, sequential identifier in the given source.
- There is no concept of the total number of pages or results in the dataset.
- The client canβt jump to a specific page.
Let us understand cursor based pagination better, with the example given below. We want to request a list of users, 2 at a time, from the server. We don't know the cursor initially, so we will assign it a null value.
{ "limit": 2, "cursor": null}
The response from the server would be:
{ "users": [ { "id": 3, "name": "Harold Osborn", "occupation": "President, Oscorp Industries", "age": 19 }, { "id": 4, "name": "Eddie Brock", "occupation": "Journalist, The Eddie Brock Report", "age": 20 } ], "next_cursor": "3"}
The next cursor returned by the server can be used to get the next set of users from the server.
{ "limit": 2, "cursor": "3"}
This is an example of forward pagination, but pagination can be done backwards too!
Implementing pagination in GraphQL
Let us look at how we can implement pagination in GraphQL.
- Implementing Offset Pagination
- Implementing Cursor Pagination
- Implementing the Relay Connection Specification