Pagination
Pagination
Pagination sets the skip and limit query parameters that select one page of a list result, and moves them forward or back between find() calls. Use it for the following tasks:
- read a large set of entries, assets, content types, global fields, or taxonomies one page at a time
- move to the next or previous page without computing skip yourself
Pagination is the base class of the query classes listed under Class-Level Notes. The SDK does not export it, so call its methods on a query object, for example stack.contentType('<CONTENT_TYPE_UID>').entry().
next
next moves the query forward by one page, by adding limit to skip.
Returns: this. The same query, for chaining.
Validation
- There is no client-side validation. next does not check whether another page exists. Past the last item, find() returns an empty list, not an error. Call includeCount() and compare count with the number of items you have read to know when to stop.
- Errors surface on the find() call that follows, not on next(). find() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. next changes skip on the query and makes no request. Call find() on the same query object to read the new page.
- When skip is above 0, next adds the current limit to it and keeps the limit. From skip 20 and limit 20, next moves to skip 40.
- Known issue: In 5.x, next sets limit to 10 when skip is 0 or unset. From the first page, it moves to skip 10 with limit 10, whatever limit you set. Set the second page with paginate({ skip, limit }), as the edge-case example below shows.
- On a query with no pagination set, next selects the second page of ten items.
- Each call moves one page, so next().next() moves two pages.
- To move back, use the previous method.
Example
Basic usage: read the first two pages of ten entries
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
const query = stack.contentType('<CONTENT_TYPE_UID>').entry().paginate();
try {
const firstPage = await query.find(); // skip 0, limit 10
const secondPage = await query.next().find(); // skip 10, limit 10
console.log('first page:', firstPage.entries?.length, 'second page:', secondPage.entries?.length);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}Edge case: keep a page size of 25 after the first page
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({ apiKey: '<API_KEY>', deliveryToken: '<DELIVERY_TOKEN>', environment: '<ENVIRONMENT>' });
const pageSize = 25;
const query = stack.contentType('<CONTENT_TYPE_UID>').entry().paginate({ limit: pageSize });
try {
const firstPage = await query.find(); // skip 0, limit 25
// From skip 0, next() would reset the limit to 10. Set the second page explicitly.
const secondPage = await query.paginate({ skip: pageSize, limit: pageSize }).find(); // skip 25, limit 25
// From a skip above 0, next() keeps the limit.
const thirdPage = await query.next().find(); // skip 50, limit 25
console.log(firstPage.entries?.length, secondPage.entries?.length, thirdPage.entries?.length);
} catch (error: any) {
console.error(error);
}paginate
paginate sets the skip and limit query parameters that select one page of results.
| Name | Type | Description |
|---|---|---|
| paginationObj.skip | number | Number of items to skip before the page starts. |
| paginationObj.limit | number | Maximum number of items on the page. |
Returns: this. The same query, for chaining.
Validation
- There is no client-side validation. paginate stores a negative skip or limit as given, and find() sends it. The API treats a negative skip as 0, and ignores a negative limit and applies its default page size.
- paginate replaces a falsy value with the default. A limit of 0 becomes 10, so paginate cannot request an empty page.
- Errors surface on the find() call that follows, not on paginate(). find() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. paginate writes skip and limit on the query and makes no request. find sends both values on that call.
- You can omit the whole object. paginate() selects the first page of ten items.
- paginate always writes both keys. paginate({ skip: 20 }) also sets limit to 10, and replaces a limit you set earlier with limit().
- Calling paginate again replaces both values.
- Use the next and previous methods to move from the current page to the one after or before it.
Example
Basic usage: read the first page of ten entries
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
try {
const result = await stack.contentType('<CONTENT_TYPE_UID>').entry().paginate().find();
console.log('entries on the first page:', result.entries?.length);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}All parameters: read the third page of 20 entries
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({ apiKey: '<API_KEY>', deliveryToken: '<DELIVERY_TOKEN>', environment: '<ENVIRONMENT>' });
interface BlogPost {
uid: string;
title: string;
}
try {
// Skip the first two pages of 20
const result = await stack
.contentType('<CONTENT_TYPE_UID>')
.entry()
.paginate({ skip: 40, limit: 20 })
.find<BlogPost>();
result.entries?.forEach((entry) => console.log(entry.title));
} catch (error: any) {
console.error(error);
}Edge case: paginate replaces a limit set earlier
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({ apiKey: '<API_KEY>', deliveryToken: '<DELIVERY_TOKEN>', environment: '<ENVIRONMENT>' });
try {
// paginate writes limit too, so the limit of 5 becomes the default of 10
const result = await stack.asset().limit(5).paginate({ skip: 10 }).find();
console.log('assets returned (at most 10):', result.assets?.length);
// Pass both values to keep a page size of 5
const pageOfFive = await stack.asset().paginate({ skip: 10, limit: 5 }).find();
console.log('assets returned (at most 5):', pageOfFive.assets?.length);
} catch (error: any) {
console.error(error);
}previous
previous moves the query back by one page, by subtracting limit from skip, and stops at 0.
Returns: this. The same query, for chaining.
Validation
- There is no client-side validation. previous never sets skip below 0, so calling it on the first page cannot fail.
- Errors surface on the find() call that follows, not on previous(). find() throws an APIError when the request fails, carrying the HTTP status, the API error_code, and the error_message.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. previous changes skip on the query and makes no request. Call find() on the same query object to read the new page.
- When skip is above 0, previous subtracts the current limit and keeps the limit. From skip 20 and limit 10, previous moves to skip 10.
- A result below 0 becomes 0. From skip 5 and limit 10, previous moves to skip 0.
- Known issue: In 5.x, when skip is 0 or unset, previous keeps skip at 0 and changes a custom limit to 10. Call previous only when skip is above 0, as the edge-case example below shows.
- To move forward, use the next method.
Example
Basic usage: move back from the third page to the second
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({
apiKey: '<API_KEY>',
deliveryToken: '<DELIVERY_TOKEN>',
environment: '<ENVIRONMENT>',
});
const query = stack.contentType('<CONTENT_TYPE_UID>').entry().paginate({ skip: 20, limit: 10 });
try {
const thirdPage = await query.find(); // skip 20, limit 10
const secondPage = await query.previous().find(); // skip 10, limit 10
console.log('third page:', thirdPage.entries?.length, 'second page:', secondPage.entries?.length);
} catch (error: any) {
// Thrown for API rejections and network failures
console.error('Request failed:', error.status, error.error_code, error.error_message);
}Edge case: skip the call on the first page to keep a custom limit
import contentstack from '@contentstack/delivery-sdk';
const stack = contentstack.stack({ apiKey: '<API_KEY>', deliveryToken: '<DELIVERY_TOKEN>', environment: '<ENVIRONMENT>' });
const pageSize = 25;
let page = 1;
const query = stack.asset().paginate({ skip: page * pageSize, limit: pageSize }); // skip 25
try {
await query.find();
// Back to the first page: skip 0, limit 25
query.previous();
page -= 1;
await query.find();
// On the first page, previous() would reset the limit to 10, so call it only when page > 0
if (page > 0) {
query.previous();
page -= 1;
}
const result = await query.find(); // still skip 0, limit 25
console.log('assets on the first page:', result.assets?.length);
} catch (error: any) {
console.error(error);
}