Edit

Share via


Pagination with after in GraphQL

Pagination narrows large datasets to smaller, manageable pages. In GraphQL, Data API builder (DAB) uses the after argument for keyset pagination, providing stable and efficient traversal through ordered results. Each cursor encodes the position of the last record in the previous page, allowing the next query to continue from that point. Unlike offset pagination, keyset pagination avoids gaps or duplicates when data changes between requests.

Go to the REST version of this document.

Quick glance

Concept Description
after The continuation token from the prior request
first The maximum number of records to fetch per page
hasNextPage Indicates whether more data exists
endCursor The token to include in the next after request

Basic pagination

GraphQL query

In this example we are getting the first three books.

query {
  books(first: 3) {
    items {
      id
      title
    }
    hasNextPage
    endCursor
  }
}

Conceptual SQL

SELECT TOP (3)
  id,
  sku_title AS title
FROM dbo.books
ORDER BY id ASC;

Sample response

{
  "data": {
    "books": {
      "items": [
        { "id": 1, "title": "Dune" },
        { "id": 2, "title": "Foundation" },
        { "id": 3, "title": "Hyperion" }
      ],
      "hasNextPage": true,
      "endCursor": "eyJpZCI6M30="
    }
  }
}

Continuation with after

The after argument specifies the continuation token for the next page. The value is a base64-encoded cursor representing the last record from the previous page.

Warning

The after argument carries an opaque token that marks where the previous page ended. Treat tokens as immutable and never attempt to construct or edit them.

In this example we are getting the next three books after the last page’s cursor.

GraphQL query

query {
  books(first: 3, after: "eyJpZCI6M30=") {
    items {
      id
      title
    }
    hasNextPage
    endCursor
  }
}

Conceptual SQL

SELECT TOP (3)
  id,
  sku_title AS title
FROM dbo.books
WHERE id > 3
ORDER BY id ASC;

Sample response

{
  "data": {
    "books": {
      "items": [
        { "id": 4, "title": "I, Robot" },
        { "id": 5, "title": "The Left Hand of Darkness" },
        { "id": 6, "title": "The Martian" }
      ],
      "hasNextPage": true,
      "endCursor": "eyJpZCI6Nn0="
    }
  }
}

Nested pagination

Pagination can be applied to related collections, such as retrieving authors with a paged list of books.

GraphQL query

query {
  authors {
    items {
      id
      name
      books(first: 2) {
        items {
          id
          title
        }
        hasNextPage
        endCursor
      }
    }
  }
}

Conceptual SQL

-- parent
SELECT
  id,
  name
FROM dbo.authors;

-- child
SELECT TOP (2)
  author_id,
  id,
  sku_title AS title
FROM dbo.books
WHERE author_id IN (@a1, @a2)
ORDER BY id ASC;

Note

Any schema or ordering change invalidates previously issued tokens. Clients must restart pagination from the first page.

Example configuration

{
  "runtime": {
    "pagination": {
      "default-page-size": 100,
      "max-page-size": 100000
    }
  },
  "entities": {
    "Book": {
      "source": {
        "type": "table",
        "object": "dbo.books"
      },
      "mappings": {
        "sku_title": "title",
        "sku_price": "price"
      },
      "relationships": {
        "book_category": {
          "cardinality": "one",
          "target.entity": "Category",
          "source.fields": [ "category_id" ],
          "target.fields": [ "id" ]
        }
      }
    },
    "Category": {
      "source": {
        "type": "table",
        "object": "dbo.categories"
      },
      "relationships": {
        "category_books": {
          "cardinality": "many",
          "target.entity": "Book",
          "source.fields": [ "id" ],
          "target.fields": [ "category_id" ]
        }
      }
    }
  }
}

See also

Concept REST GraphQL Purpose
Projection $select items Choose which fields to return
Filtering $filter filter Restrict rows by condition
Sorting $orderby orderBy Define the sort order
Page size $first first Limit the number of items per page
Continuation $after after Continue from the last page using a cursor

Note

REST keywords begin with $, following OData conventions.