Pagination

Relay cursor-based pagination

Pagination

List endpoints in the API use Relay cursor-based pagination. This provides stable, efficient pagination over large datasets.

Connection shape

Paginated results follow the Relay connection pattern:

type AccountConnection {
  nodes: [Account]!
  edges: [AccountEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

type AccountEdge {
  cursor: String!
  node: Account!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}
FieldDescription
nodesFlat array of items on the current page
edgesArray of { cursor, node } pairs
pageInfoPagination metadata
totalCountTotal number of items across all pages

Forward pagination

Use first and after to paginate forward:

query Accounts($first: Int!, $after: String) {
  accounts(first: $first, after: $after) {
    edges {
      cursor
      node {
        id
        status
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

First page — omit after:

{ "first": 20 }

Next page — pass endCursor from the previous response as after:

{ "first": 20, "after": "YXJyYXljb25uZWN0aW9uOjIw" }

Stop when pageInfo.hasNextPage is false.

Backward pagination

Use last and before to paginate backward. Do not combine first with last in the same request.

query Accounts($last: Int!, $before: String) {
  accounts(last: $last, before: $before) {
    edges {
      cursor
      node { id }
    }
    pageInfo {
      hasPreviousPage
      startCursor
    }
  }
}

Example: paginate through all accounts

async function fetchAllAccounts(client: GraphQLClient) {
  const accounts = [];
  let cursor: string | null = null;
  let hasNextPage = true;

  while (hasNextPage) {
    const { data } = await client.query({
      query: ACCOUNTS_QUERY,
      variables: { first: 50, after: cursor },
    });

    for (const edge of data.accounts.edges) {
      accounts.push(edge.node);
    }

    hasNextPage = data.accounts.pageInfo.hasNextPage;
    cursor = data.accounts.pageInfo.endCursor;
  }

  return accounts;
}

Tips

  • Use nodes when you only need the items (simpler). Use edges when you need cursors for pagination.
  • Page sizes of 20–50 are typical. Very large first values may hit complexity limits.
  • Cursors are opaque strings — do not parse or construct them manually.

Did this page help you?