Pagination
Pagination lets you retrieve large sets of records by breaking them into manageable chunks — helping optimize performance and reduce data transfer.
Limit results with first
Control the number of elements returned in a single query using the first parameter:
Default limit: 20 records
Maximum limit: 500 records
The following query returns the first 5 artist records:
{ allArtists(first: 5) { id name }} Skip records with skip
Use the skip parameter to offset your results, allowing you to implement pagination across multiple requests:
{ allArtists(first: 5, skip: 10) { id name }}This query skips the first 10 records and returns the next 5.
Calculating the total number of results
To determine the total number of records — typically to implement client-side pagination — use the _XXXMeta query:
query { allArtists(filter: { name: { in: ["Blank Banshee", "Gazelle Twin"] } }) { id name genre } _allArtistsMeta(filter: { name: { in: ["Blank Banshee", "Gazelle Twin"] } }) { count }}Make sure to apply the same filters to both your regular query and the meta query, otherwise the two counts will diverge!
Auto-pagination beyond the 500-record limit
A single CDA query can return at most 500 records per collection. For larger result sets, the @datocms/cda-client package ships an executeQueryWithAutoPagination helper that rewrites the query on the fly into multiple aliased selections, executes it in a single round-trip, and stitches the results back together — transparently:
import { executeQueryWithAutoPagination } from '@datocms/cda-client';
const result = await executeQueryWithAutoPagination( `query BuildSitemapUrls { entries: allSuccessStories(first: 2500) { slug } }`, { token: process.env.DATOCMS_READONLY_TOKEN },);How it works
Suppose you want to execute the following query on a model with 2,500 records:
query BuildSitemapUrls { allBlogPosts { slug }
entries: allSuccessStories(first: 2500) { ...SuccessStoryUrlFragment }}
fragment SuccessStoryUrlFragment on SuccessStoryRecord { slug}The CDA returns at most 500 items at a time. Normally you'd paginate manually by issuing the same query five times, each with an incremented skip. executeQueryWithAutoPagination does it for you in a single round-trip by rewriting the query like this:
query BuildSitemapUrls { allBlogPosts { slug } splitted_0_entries: allSuccessStories(first: 500, skip: 0) { ...SuccessStoryUrlFragment } splitted_500_entries: allSuccessStories(first: 500, skip: 500) { ...SuccessStoryUrlFragment } splitted_1000_entries: allSuccessStories(first: 500, skip: 1000) { ...SuccessStoryUrlFragment } splitted_1500_entries: allSuccessStories(first: 500, skip: 1500) { ...SuccessStoryUrlFragment } splitted_2000_entries: allSuccessStories(first: 500, skip: 2000) { ...SuccessStoryUrlFragment }}
fragment SuccessStoryUrlFragment on SuccessStoryRecord { slug}Once executed, the results are collected and recomposed as if nothing happened.
Limitations
The query may contain at most one selection with an oversized
first:argument. If two or more collections exceed 500 records in the same query, the helper throws.The rewritten query must still respect the GraphQL complexity cost limit.
Reading cache tags alongside auto-pagination
A rawExecuteQueryWithAutoPagination variant is also available, with the same [result, response] return shape as rawExecuteQuery. It's useful when you need to combine auto-pagination with Cache Tags:
import { rawExecuteQueryWithAutoPagination } from '@datocms/cda-client';
const [result, response] = await rawExecuteQueryWithAutoPagination(query, { token: process.env.DATOCMS_READONLY_TOKEN, returnCacheTags: true,});
const cacheTags = response.headers.get('x-cache-tags');You can find the complete API reference in the @datocms/cda-client README.