Content Delivery API

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.

Last updated: