---
title: "Pagination"
description: "Cursor-based pagination for WPGraphQL connections"
canonical_url: "https://wpnuxt.com/guide/pagination"
---
# Pagination

> Cursor-based pagination for WPGraphQL connections

WPGraphQL uses cursor-based pagination via the Relay connection pattern. When your query includes `pageInfo`, WPNuxt automatically generates a composable with pagination support — including `pageInfo`, `loadMore()`, and full type safety.

## Setup

Create a query in `extend/queries/` that includes `pageInfo` alongside `nodes`:

```graphql [extend/queries/PaginatedPosts.gql]
query PaginatedPosts($first: Int, $after: String, $last: Int, $before: String) {
  posts(first: $first, after: $after, last: $last, before: $before) {
    pageInfo {
      hasNextPage
      hasPreviousPage
      endCursor
      startCursor
    }
    nodes {
      ...Post
    }
  }
}
```

Run `pnpm nuxt prepare` to generate the composable. `usePaginatedPosts()` is now available with pagination support.

## Infinite Scroll

Use `loadMore()` to fetch the next page and append items to the list. Items accumulate automatically:

```vue
<script setup lang="ts">
const { data: posts, pageInfo, loadMore, pending } = await usePaginatedPosts({ first: 10 })
</script>

<template>
  <article v-for="post in posts" :key="post.databaseId">
    <h2>{{ post.title }}</h2>
  </article>

  <button
    v-if="pageInfo?.hasNextPage"
    :disabled="pending"
    @click="loadMore"
  >
    Load more
  </button>
</template>
```

Each call to `loadMore()` fetches the next page using the current `endCursor` and appends the results. Call `refresh()` to reset back to the first page.

## Page-based Navigation

For previous/next page navigation, manage the cursor yourself with reactive params:

```vue
<script setup lang="ts">
const after = ref<string>()
const before = ref<string>()

const params = computed(() => {
  if (before.value) {
    return { last: 10, before: before.value }
  }
  return { first: 10, after: after.value }
})

const { data: posts, pageInfo, pending } = await usePaginatedPosts(params)

function nextPage() {
  if (pageInfo.value?.hasNextPage && pageInfo.value.endCursor) {
    before.value = undefined
    after.value = pageInfo.value.endCursor
  }
}

function previousPage() {
  if (pageInfo.value?.hasPreviousPage && pageInfo.value.startCursor) {
    after.value = undefined
    before.value = pageInfo.value.startCursor
  }
}
</script>

<template>
  <article v-for="post in posts" :key="post.databaseId">
    <h2>{{ post.title }}</h2>
  </article>

  <div>
    <button v-if="pageInfo?.hasPreviousPage" @click="previousPage">
      ← Previous
    </button>
    <button v-if="pageInfo?.hasNextPage" @click="nextPage">
      Next →
    </button>
  </div>
</template>
```

<callout type="info">

When using page-based navigation with reactive params, pass `{ clientCache: false }` as an option to ensure each page fetch hits the server.

</callout>

## How It Works

WPNuxt detects the connection pattern (`pageInfo` + `nodes` as sibling fields) during query parsing. When detected, the generated composable uses `useWPConnection` instead of `useWPContent`, which:

1. Extracts `nodes` as `data` (the items array)
2. Extracts `pageInfo` separately
3. Provides `loadMore()` for accumulation
4. Handles `refresh()` with accumulation reset

This is fully automatic — just add `pageInfo` to your query and the composable gains pagination capabilities.

## Related Pages

- **Custom Queries** — How to create the paginated query
- **Composables Reference** — Full API reference for connection queries
- **Fetching Data** — Reactive params and other composable options


## Sitemap

See the full [sitemap](https://wpnuxt.com/sitemap.md) for all pages.
