Shopify Functions & APIs

Shopify GraphQL Pagination: Cursors, Limits and Bulk Exports

By CartStack Team3 min read

Shopify GraphQL pagination is how you read more than one page of data from the Admin API. It uses cursors instead of page numbers. This guide shows the query, a working loop, and the point where you should switch to bulk operations.

Cover graphic for Shopify GraphQL pagination with cursors
Shopify GraphQL pagination walks a connection one cursor at a time.

How Shopify GraphQL pagination works

Every list in the Admin API is a connection. You ask for the first N items and a cursor. Then you pass that cursor back to get the next page.

The response includes a pageInfo object. It tells you whether more data exists. Also, the largest page size is 250 items.

query Products($cursor: String) {
  products(first: 100, after: $cursor) {
    edges { node { id title } }
    pageInfo { hasNextPage endCursor }
  }
}

Loop through every page

Next, wrap the query in a loop. Keep going while hasNextPage is true. Save the endCursor each time.

const API_VERSION = '2025-10'; // use a supported version

async function fetchAllProducts(shop, token) {
  const products = [];
  let cursor = null;
  let hasNextPage = true;

  while (hasNextPage) {
    const res = await fetch(`https://${shop}/admin/api/${API_VERSION}/graphql.json`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Shopify-Access-Token': token,
      },
      body: JSON.stringify({ query: QUERY, variables: { cursor } }),
    });
    const { data, extensions } = await res.json();

    const page = data.products;
    products.push(...page.edges.map((edge) => edge.node));
    hasNextPage = page.pageInfo.hasNextPage;
    cursor = page.pageInfo.endCursor;

    const { currentlyAvailable, restoreRate } = extensions.cost.throttleStatus;
    if (currentlyAvailable < 200) {
      await new Promise((r) => setTimeout(r, (200 / restoreRate) * 1000));
    }
  }
  return products;
}

Notice that the loop reads the cost data. This detail matters, so the next section explains it.

Respect cost limits in Shopify GraphQL pagination

The Admin API does not count requests. Instead, it charges a cost for each query. Every store has a bucket of points that refills over time. Standard plans get a smaller bucket and refill rate than Plus.

The response includes extensions.cost. It shows the requested cost, the actual cost and the throttle status. So you can pause when the bucket runs low.

Two habits keep your cost down. First, request only the fields you need. Second, avoid deeply nested connections, because cost multiplies at each level. Read the official rate limit documentation for the current numbers.

Switch to bulk operations for large exports

Pagination works well for a few thousand records. However, it gets slow and fragile for a full catalog. In that case, use a bulk operation.

A bulk operation runs your query in the background. Shopify then gives you a URL to a JSONL file. As a result, you avoid the rate limits of paging.

mutation {
  bulkOperationRunQuery(
    query: """
    {
      products {
        edges { node { id title } }
      }
    }
    """
  ) {
    bulkOperation { id status }
    userErrors { field message }
  }
}

Then wait for the operation to finish. You can poll its status or subscribe to the bulk_operations/finish webhook. Finally, download the file and read it line by line.

Common pagination mistakes

  • Using page numbers or offsets. The API only supports cursors.
  • Reusing an old cursor after the data changed.
  • Ignoring userErrors and the cost data in the response.
  • Paging a huge catalog when a bulk operation would finish sooner.

Building automation on top of this? You may also want Shopify Functions for checkout logic. For every field and argument, see the Admin GraphQL API reference.

FAQ about Shopify GraphQL pagination

What is the maximum page size? You can request up to 250 items per page.

Can I jump to page five? No. Cursor pagination is sequential, so you must walk the pages in order.

Should I still use the REST API? No. Shopify treats REST as legacy, so build new work on GraphQL.