---
title: Pagination
description: >-
  The Storefront API uses cursors to paginate through lists of data and the
  &lt;Pagination /&gt; component makes it easy to paginate data from the
  Storefront API.
api_version: 2026-04
api_name: hydrogen
source_url:
  html: 'https://shopify.dev/docs/api/hydrogen/latest/components/pagination'
  md: 'https://shopify.dev/docs/api/hydrogen/latest/components/pagination.md'
---

# Pagination

The [Storefront API uses cursors](https://shopify.dev/docs/api/usage/pagination-graphql) to paginate through lists of data and the `<Pagination />` component makes it easy to paginate data from the Storefront API. It is important for pagination state to be maintained in the URL, so that the user can navigate to a product and return back to the same scrolled position in a list. It is also important that the list state is shareable via URL. The `<Pagination>` component provides a render prop with properties to load more elements into your list.

#### Props

* **children**

  **PaginationRenderProp\<NodesType>**

  **required**

  A render prop that includes pagination data and helpers.

* **connection**

  **Connection\<NodesType>**

  **required**

  The response from `storefront.query` for a paginated request. Make sure the query is passed pagination variables and that the query has `pageInfo` with `hasPreviousPage`, `hasNextpage`, `startCursor`, and `endCursor` defined.

* **namespace**

  **string**

  A namespace for the pagination component to avoid URL param conflicts when using multiple `Pagination` components on a single page.

### PaginationRenderProp

* contextTypes

  ```ts
  ValidationMap<any> | undefined
  ```

* defaultProps

  Used to define default values for the props accepted by the component.

  ```ts
  Partial<P> | undefined
  ```

* displayName

  Used in debugging messages. You might want to set it explicitly if you want to display a different name for debugging purposes.

  ```ts
  string | undefined
  ```

* propTypes

  Used to declare the types of the props accepted by the component. These types will be checked during rendering and in development only. We recommend using TypeScript instead of checking prop types at runtime.

  ```ts
  WeakValidationMap<P> | undefined
  ```

### Connection

```ts
{
      nodes: Array<NodesType>;
      pageInfo: PageInfo;
    } | {
      edges: Array<{
        node: NodesType;
      }>;
      pageInfo: PageInfo;
    }
```

Examples

### Examples

* #### Example code

  ##### JavaScript

  ```jsx
  import {Pagination, getPaginationVariables} from '@shopify/hydrogen';
  import {useLoaderData, Link} from 'react-router';

  export async function loader({request, context: {storefront}}) {
    const variables = getPaginationVariables(request, {pageBy: 8});

    const data = await storefront.query(ALL_PRODUCTS_QUERY, {
      variables,
    });

    return {products: data.products};
  }

  export default function List() {
    const {products} = useLoaderData();

    return (
      <Pagination connection={products}>
        {({nodes, PreviousLink, NextLink}) => (
          <>
            <PreviousLink>Previous</PreviousLink>
            <div>
              {nodes.map((product) => (
                <Link key={product.id} to={`/products/${product.handle}`}>
                  {product.title}
                </Link>
              ))}
            </div>
            <NextLink>Next</NextLink>
          </>
        )}
      </Pagination>
    );
  }

  const ALL_PRODUCTS_QUERY = `#graphql
    query AllProducts(
      $country: CountryCode
      $language: LanguageCode
      $first: Int
      $last: Int
      $startCursor: String
      $endCursor: String
    ) @inContext(country: $country, language: $language) {
      products(first: $first, last: $last, before: $startCursor, after: $endCursor) {
        nodes { id
          title
          handle
        }
        pageInfo {
          hasPreviousPage
          hasNextPage
          startCursor
          endCursor
        }
      }
    }
  `;
  ```

  ##### TypeScript

  ```tsx
  import {type LoaderFunctionArgs} from 'react-router';
  import {Pagination, getPaginationVariables} from '@shopify/hydrogen';
  import {useLoaderData, Link} from 'react-router';
  import {ProductConnection} from '@shopify/hydrogen/storefront-api-types';

  export async function loader({
    request,
    context: {storefront},
  }: LoaderFunctionArgs) {
    const variables = getPaginationVariables(request, {pageBy: 8});

    const data = await storefront.query<{products: ProductConnection}>(
      ALL_PRODUCTS_QUERY,
      {
        variables,
      },
    );

    return {products: data.products};
  }

  export default function List() {
    const {products} = useLoaderData<typeof loader>();

    return (
      <Pagination connection={products}>
        {({nodes, NextLink, PreviousLink}) => (
          <>
            <PreviousLink>Previous</PreviousLink>
            <div>
              {nodes.map((product) => (
                <Link key={product.id} to={`/products/${product.handle}`}>
                  {product.title}
                </Link>
              ))}
            </div>
            <NextLink>Next</NextLink>
          </>
        )}
      </Pagination>
    );
  }

  const ALL_PRODUCTS_QUERY = `#graphql
    query AllProducts(
      $country: CountryCode
      $language: LanguageCode
      $first: Int
      $last: Int
      $startCursor: String
      $endCursor: String
    ) @inContext(country: $country, language: $language) {
      products(first: $first, last: $last, before: $startCursor, after: $endCursor) {
        nodes { id
          title
          handle
        }
        pageInfo {
          hasPreviousPage
          hasNextPage
          startCursor
          endCursor
        }
      }
    }
  `;
  ```

***

## Related

[- getPaginationVariables](https://shopify.dev/docs/api/hydrogen/2026-04/utilities/getpaginationvariables)

***
