Skip to main content
Our docs redesign is live!

Rewrite queries, pagination, sorting, and field selection

4 min read

Query migration is where most applications spend their time. A page may render correctly with a single entry fetch, but listing pages, search pages, reference-heavy pages, and route discovery usually rely on query chains.

What you'll learn

  • How JavaScript SDK query chains map to TypeScript Delivery SDK query chains

  • How to migrate filters, references, sorting, and pagination

  • How to select or exclude fields

  • How to keep query helpers readable

  • Which limitations to remember while testing

Start from the query object

JavaScript SDK:

const Query = Stack.ContentType('blog').Query();

const result = await Query
  .where('featured', true)
  .includeReference('author')
  .descending('published_date')
  .limit(10)
  .toJSON()
  .find();

TypeScript Delivery SDK:

const query = stack.contentType('blog').entry().query();

const result = await query
  .equalTo('featured', true)
  .includeReference('author')
  .orderByDescending('published_date')
  .limit(10)
  .find();

The main changes are the query starting point and the sorting method names.

Common query translations

Use this table as a migration checklist:

JavaScript Delivery SDK

TypeScript Delivery SDK

Stack.ContentType('blog').Query()

stack.contentType('blog').entry().query()

.ascending('title')

.orderByAscending('title')

.descending('date')

.orderByDescending('date')

.language('fr-fr')

.locale('fr-fr')

.addParam(key, value)

.param(key, value) or .addParams({ [key]: value })

.toJSON().find()

.find()

.toJSON().fetch()

.fetch()

Do not migrate every query by search-and-replace alone. The old SDK has patterns such as Query().findOne() and query-level cache policy calls that may need a more deliberate rewrite.

Field selection

Use only() when a route or listing page needs a small payload:

const result = await stack.contentType('blog')
  .entry()
  .only('title', 'url', 'published_date')
  .find();

Use except() when most fields are useful but a few should stay out of the response:

const result = await stack.contentType('blog')
  .entry()
  .except('internal_notes')
  .find();

If your app includes large references, rich text fields, or asset-heavy modular blocks, field selection can be part of the migration instead of a later optimization.

References and embedded items

Reference-heavy pages are common in Contentstack projects. Migrate them explicitly:

const page = await stack.contentType('page')
  .entry('entry_uid')
  .includeReference('sections.author', 'related_posts')
  .includeEmbeddedItems()
  .fetch()

For collection queries:

const pages = await stack.contentType('page')
  .entry()
  .query()
  .includeReference('sections.author', 'related_posts')
  .includeEmbeddedItems()
  .find();

After migration, compare reference depth and embedded item behavior on pages that use rich text, modular blocks, or shared components.

Filtering

Simple equality filters can be expressed with equalTo():

const result = await stack.contentType('product')
  .entry()
  .query()
  .equalTo('category', 'rings')
  .find();

For list-style filters, use methods such as containedIn() and notContainedIn():

const result = await stack.contentType('product')
  .entry()
  .query()
  .containedIn('tags', ['featured', 'new'])
  .find();

For range, existence, search, tags, taxonomy, and reference filters, migrate each helper by checking the TypeScript Delivery SDK reference. The methods are familiar, but exact names and argument order matter.

Pagination

Traditional skip and limit still work:

const result = await stack.contentType('blog')
  .entry()
  .query()
  .skip(20)
  .limit(20)
  .find();

The TypeScript Delivery SDK also supports pagination helpers:

const query = stack.contentType('blog').entry().query();

const firstPage = await query.paginate().find();
const nextPage = await query.next().find();
const previousPage = await query.previous().find();

Use the style that best matches your UI and existing route behavior. For numbered pages, skip() and limit() may be easiest to keep. For cursor-like navigation, pagination helpers can keep the code clearer.

Sorting

Replace old sort helpers with the explicit ordering methods:

const newest = await stack.contentType('blog')
  .entry()
  .query()
  .orderByDescending('published_date')
  .find();

const alphabetical = await stack.contentType('blog')
  .entry()
  .query()
  .orderByAscending('title')
  .find();

Be careful with routes that relied on default ordering. If the old SDK and the new SDK return entries in a different order, add an explicit sort.

Limits to remember

The current TypeScript Delivery SDK has a few practical limits to keep in mind:

  • Content Delivery API requests that exceed the CDN URL size limit can fail.

  • Multiple content type referencing in a single query is not supported.

  • Global field schema querying is not exposed as a standalone query, but content type details can include global field schema data.

These limits are easiest to catch with real migrated pages, not isolated examples.

Key takeaways

  • Start entry queries with stack.contentType(uid).entry().query().

  • Replace ascending() and descending() with orderByAscending() and orderByDescending().

  • Keep skip() and limit() when they match your current pagination model.

  • Compare reference and embedded item responses on complex pages.

  • Add explicit sorting when page order matters.

Frequently asked questions

  • What is the equivalent of Stack.ContentType('blog').Query() in the TypeScript Delivery SDK?

    Use stack.contentType('blog').entry().query(). This is the new starting point for collection queries.

  • How do I migrate ascending() and descending() sorting methods?

    Replace them with orderByAscending(field) and orderByDescending(field). Add explicit sorting if route order matters.

  • How do only() and except() help during migration?

    only() returns a small set of fields to reduce payload on listings and routes. except() excludes specific fields when most of the entry is still needed.

  • How do I migrate reference-heavy queries and embedded items?

    Use includeReference() with the relevant reference paths and includeEmbeddedItems() for rich text and modular block embedded items. Validate output depth and structure on real pages after migration.

  • What pagination options are available in the TypeScript Delivery SDK?

    You can keep skip() and limit() for offset-based pagination, or use paginate() with next() and previous() for cursor-like navigation.