Vue Guide
Pagination
Build client-side paginated feeds with useConvexPaginatedQuery and Convex paginated query functions.
Use useConvexPaginatedQuery when you want a client-side feed that loads one page at a time and stays subscribed as more data arrives.
Write the Convex query
Your Convex query must accept paginationOpts and return a PaginationResult.
convex/tasks.ts
import { paginationOptsValidator } from 'convex/server'
import { v } from 'convex/values'
import { query } from './_generated/server'
export const paginated = query({
args: {
status: v.optional(v.string()),
paginationOpts: paginationOptsValidator,
},
handler: async (ctx, { status, paginationOpts }) => {
let q = ctx.db.query('tasks').order('desc')
if (status)
q = q.filter(doc => doc.eq(doc.field('status'), status))
return await q.paginate(paginationOpts)
},
})
You do not pass paginationOpts from the component. useConvexPaginatedQuery injects it for you.
Subscribe from the client
src/components/TaskFeed.vue
<script setup lang="ts">
import { useConvexPaginatedQuery } from 'vue-convex'
import { api } from '../convex/_generated/api'
const { data, isPending, isDone, isLoadingMore, loadMore } = useConvexPaginatedQuery(
api.tasks.paginated,
{},
{ numItems: 20 },
)
</script>
Reset on filter changes
Reactive arguments automatically clear the current pages and restart from the first page.
src/components/FilteredFeed.vue
<script setup lang="ts">
import { useConvexPaginatedQuery } from 'vue-convex'
import { api } from '../convex/_generated/api'
const status = ref('active')
const { data, loadMore, isDone } = useConvexPaginatedQuery(
api.tasks.paginated,
computed(() => ({ status: status.value })),
{ numItems: 20 },
)
</script>
Skip pagination until the inputs exist
const { data, isSkipped } = useConvexPaginatedQuery(
api.tasks.paginated,
computed(() => userId.value ? { userId: userId.value } : 'skip'),
{ numItems: 20 },
)
Use the optimistic helpers when needed
The package exports helpers such as insertAtTop, insertAtBottomIfLoaded, insertAtPosition, and optimisticallyUpdateValueInPaginatedQuery for use inside mutation optimistic updates.
Verify the result
The setup is working when:
- the first page loads into
data loadMore()appends another page- changing the arguments resets the feed
useConvexPaginatedQuery is client-only. It does not run an SSR prefetch pass.
Next steps
- Read File Storage if each item in the feed needs uploads or file URLs
- Read
useConvexPaginatedQueryfor the exact return shape