GraphQL pagination

In this guide you will learn how to implement pagination in your GraphQL API.

When working with a large record set, you may want to only fetch the first N number of items. For example, let's start with a basic GraphQL schema for a Todo app:

type Todo @model { id: ID! title: String! description: String }
1type Todo @model {
2 id: ID!
3 title: String!
4 description: String
5}

When the API is created with an @model directive, the following queries will automatically be created for you:

type Query { getTodo(id: ID!): Todo listTodos( filter: ModelTodoFilterInput limit: Int nextToken: String ): ModelTodoConnection }
1type Query {
2 getTodo(id: ID!): Todo
3 listTodos(
4 filter: ModelTodoFilterInput
5 limit: Int
6 nextToken: String
7 ): ModelTodoConnection
8}

Next, take a look at the ModelTodoConnection type to get an idea of the data that will be returned when the listTodos query is run:

type ModelTodoConnection { items: [Todo] nextToken: String }
1type ModelTodoConnection {
2 items: [Todo]
3 nextToken: String
4}

When querying the API using the listTodos query, the return type will be of ModelTodoConnection, meaning you can return both an array of Todos and a nextToken.

The nextToken is what is used to handle pagination. If the nextToken is null, that means that there is no more data to return from the API. If the nextToken is present, you can use the value as an argument to the next listTodos query to return the next selection set from the API.

To test this out, try creating 5 todos using a mutation like this:

mutation createTodo { createTodo(input: { title: "Todo 1" description: "My first todo" }) { id title description } }
1mutation createTodo {
2 createTodo(input: {
3 title: "Todo 1"
4 description: "My first todo"
5 }) {
6 id
7 title
8 description
9 }
10}

Next, you can set the limit of the number of todos in a query by passing in a limit argument. In this query, you'll set the limit to 2 items and request a nextToken as a return value:

query listTodos { listTodos(limit: 2) { items { id title description } nextToken } }
1query listTodos {
2 listTodos(limit: 2) {
3 items {
4 id
5 title
6 description
7 }
8 nextToken
9 }
10}

Now, to query the next 2 items from the API, you can pass this nextToken as the argument:

query listTodos { listTodos(limit: 2, nextToken: <your_token>) { items { id title description } nextToken } }
1query listTodos {
2 listTodos(limit: 2, nextToken: <your_token>) {
3 items {
4 id
5 title
6 description
7 }
8 nextToken
9 }
10}

When there are no other items left to be returned, the nextToken in the response will be set to null.

Querying from a JavaScript application

The listTodos query should have been created for you automatically by the CLI, but for reference purposes it should look something like this:

const listTodos = ` query listTodos($limit: Int) { listTodos(limit: $limit) { items { id title description } nextToken } } `
1const listTodos = `
2 query listTodos($limit: Int) {
3 listTodos(limit: $limit) {
4 items {
5 id
6 title
7 description
8 }
9 nextToken
10 }
11 }
12`

To pass in a limit in a query from a JavaScript application, you can use the following code by setting the limit as a variable:

import { API } from 'aws-amplify'; async function fetchTodos() { const todoData = await API.graphql({ query: listTodos, variables: { limit: 2 } }) console.log({ todoData }) }
1import { API } from 'aws-amplify';
2
3async function fetchTodos() {
4 const todoData = await API.graphql({
5 query: listTodos,
6 variables: {
7 limit: 2
8 }
9 })
10 console.log({ todoData })
11}

The data returned from the API request should look like this (with the items array containing however many items have been created):

{ "data" { "listTodos" { "items": [{ id: "001", title: "Todo 1", description: "My first todo" }], "nextToken": "<token-id>" } } }
1{
2 "data" {
3 "listTodos" {
4 "items": [{ id: "001", title: "Todo 1", description: "My first todo" }],
5 "nextToken": "<token-id>"
6 }
7 }
8}

To set the nextToken in a query from a JavaScript application, you can use the following code:

import { API } from 'aws-amplify'; async function fetchTodos() { const todoData = await API.graphql({ query: listTodos, variables: { limit: 2, nextToken: "<token-id>" } }) console.log({ todoData }) }
1import { API } from 'aws-amplify';
2
3async function fetchTodos() {
4 const todoData = await API.graphql({
5 query: listTodos,
6 variables: {
7 limit: 2,
8 nextToken: "<token-id>"
9 }
10 })
11 console.log({ todoData })
12}