Skip to main content

GraphQL pagination

GraphQL lists are paginated by cursor: items inserted or removed while navigating do not shift the pages.

Response structure​

Every paginated query returns a Connection:

type Connection {
pageInfo: PageInfo!
edges: [Edge!]!
}

type Edge {
cursor: String!
node: <EntityType>!
}

type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
total: Int!
}

total is the overall number of results, regardless of pagination.

Pagination input​

input PaginationInput {
first: Int # how many items to take from the head
last: Int # how many items to take from the tail
after: String # cursor: take the items after this one
before: String # cursor: take the items before this one
}

Without first or last the page has 25 items. first and last cannot be used together.

Forward navigation​

Use first and after.

First page:

query {
donations(pagination: { first: 20 }) {
pageInfo {
hasNextPage
endCursor
total
}
edges {
cursor
node {
id
state
amount
}
}
}
}

Next page, with the endCursor of the previous response:

query {
donations(pagination: { first: 20, after: "Y3Vyc29yOnYxOjIwMjMtMDgtMTd8MTIz" }) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
id
state
amount
}
}
}
}

Backward navigation​

Use last and before.

query {
donations(pagination: { last: 20, before: "Y3Vyc29yOnYxOjIwMjMtMDgtMTd8MTIz" }) {
pageInfo {
hasPreviousPage
startCursor
}
edges {
node {
id
state
amount
}
}
}
}

How cursors work​

Cursors are Base64 strings that encode the item's ordering fields (for example payment_date|id). Do not build them by hand: use the ones returned in startCursor, endCursor or edges[*].cursor.

Fetching all items​

Iterate on hasNextPage and endCursor:

async function fetchAll(client) {
let after = null;
const results = [];

do {
const { data } = await client.query({
query: DONATIONS_QUERY,
variables: { pagination: { first: 100, after } },
});

results.push(...data.donations.edges.map(e => e.node));
after = data.donations.pageInfo.hasNextPage
? data.donations.pageInfo.endCursor
: null;
} while (after);

return results;
}

Queries that support pagination​

These accept pagination: PaginationInput:

  • donations
  • payments
  • supporters
  • campaigns
  • checkouts
  • activities