# References, includes, and localized content retrieval

### About this export

| Field | Value |
| --- | --- |
| **content_type** | lesson |
| **platform** | contentstack-academy |
| **source_url** | https://www.contentstack.com/academy/courses/apis-and-developer-tooling/references-includes-and-localized-content-retrieval |
| **course_slug** | apis-and-developer-tooling |
| **lesson_slug** | references-includes-and-localized-content-retrieval |
| **markdown_file_url** | /academy/md/courses/apis-and-developer-tooling/references-includes-and-localized-content-retrieval.md |
| **generated_at** | 2026-08-03T11:49:30.830Z |

> Part of **[APIs and Developer Tooling](https://www.contentstack.com/academy/courses/apis-and-developer-tooling)** on Contentstack Academy. **Academy MD v3** — structured for retrieval; no quiz or assessment keys.

<!-- ai_metadata: {"lesson_id":"09","type":"text","duration_minutes":1,"topics":["References","includes","and","localized","content","retrieval"]} -->

#### Lesson text

# References, includes, and localized content retrieval

> **TL;DR**
> 
> *   Use includeReference() (or include\[\] in REST) with the reference _field UID_ to resolve related entries in a single API call instead of making N+1 separate requests.
> *   Always enable include\_fallback on partially localized stacks so visitors see parent-locale content instead of blank fields for untranslated entries.
> *   Limit include depth to what the current view actually renders -- each additional level multiplies response payload and latency.

Content in Contentstack rarely lives in isolation. A product entry references its category and product line. A page references its components. Understanding how references resolve at the API level - and how localization interacts with that resolution - is essential to building correct, performant delivery code.

This lesson uses a **Product** content type from Veda: The Revival Collection with referenced **Category** and **Product Line** entries to illustrate every concept.

## How references work at the data level

A reference field in Contentstack stores an array of objects, each containing the UID and content type of the referenced entry. When you fetch a product entry without any include parameters, the reference field looks like this:

{
  "title": "Matrix Link Bracelet",
  "url": "/products/digital-dawn/matrix-link-bracelet",
  "price": 295,
  "short\_description": "A sleek link bracelet composed of interlocking square links...",
  "category": \[
    {
      "uid": "blt8a3f2e1d0c9b7a65",
      "\_content\_type\_uid": "category"
    }
  \],
  "product\_line": \[
    {
      "uid": "blt2a4b6c8d0e1f3759",
      "\_content\_type\_uid": "product\_line"
    }
  \]
}

Notice: you get the UIDs and content type identifiers, but not the actual data of those categories or product lines. The referenced entries' titles, descriptions, images, and other fields are not included. To render "Digital Dawn - Bracelets" on the page, you need to resolve these references.

There are two ways to resolve them: multiple separate API calls (inefficient) or the include mechanism (correct).

## The include\[\] parameter in REST

The REST Content Delivery API supports an include\[\] query parameter that tells the API to resolve specified reference fields and embed the full referenced entries in the response.

GET /v3/content\_types/product/entries?environment=production&include\[\]=category&include\[\]=product\_line

With this parameter, the response transforms. Instead of UID stubs, each referenced entry is expanded inline.

{
  "title": "Matrix Link Bracelet",
  "category": \[
    {
      "uid": "blt8a3f2e1d0c9b7a65",
      "title": "Bracelets",
      "url": "/category/bracelets",
      "description": "Link bracelets, cuffs, and bangles",
      "\_content\_type\_uid": "category"
    }
  \],
  "product\_line": \[
    {
      "uid": "blt2a4b6c8d0e1f3759",
      "title": "Digital Dawn",
      "url": "/products/digital-dawn",
      "description": "Y2K-inspired unisex jewelry in silver and gold",
      "image": { "url": "https://images.contentstack.io/..." },
      "\_content\_type\_uid": "product\_line"
    }
  \]
}

Each include\[\] value is the field UID of the reference field on the parent content type, not the UID of the referenced content type. This distinction matters: if your product has two reference fields both pointing to the category content type (for example, primary\_category and secondary\_category), you include them separately:

include\[\]=primary\_category&include\[\]=secondary\_category

## The includeReference() method in the SDK

The JavaScript SDK wraps the include\[\] parameter with the includeReference() method.

import Contentstack from "@contentstack/delivery-sdk";

const stack = Contentstack.stack({
  apiKey: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY,
  deliveryToken: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_DELIVERY\_TOKEN,
  environment: "production",
  region: Contentstack.Region.EU,
});

async function getProductWithDetails(slug: string) {
  const query = stack.contentType("product").entry().query();

  const result = await query
    .equalTo("url", \`/products/digital-dawn/${slug}\`)
    .includeReference("category")
    .includeReference("product\_line")
    .find();

  return result.entries\[0\];
}

const product = await getProductWithDetails("matrix-link-bracelet");

// Category and product line are now full objects
product.category.forEach((cat) => {
  console.log(\`${cat.title} - ${cat.url}\`);
});

// Product line is resolved
console.log(\`From ${product.product\_line\[0\].title} collection\`);

Chain .includeReference() calls for each reference field UID you need resolved. The SDK appends the appropriate parameters to the request automatically.

## Include depth: nested references

References can be nested. A product references its product line, and each product line has a products field referencing other products. To resolve both levels, you need nested include paths.

In the REST API, you express this with dot notation:

include\[\]=product\_line.products

In the SDK, you use the same dot notation:

const result = await query
  .includeReference("product\_line.products")
  .includeReference("category")
  .find();

// Access nested reference - other products in the same line
product.product\_line\[0\].products\[0\].title; // "Pixel Stud Earrings"

### Performance implications of include depth

Every level of include depth increases the work the API must do. Contentstack resolves includes server-side by performing additional internal lookups.

The practical lookup limits behave as follows:

*   **One level (e.g.,** **category****):** Standard and performant. This is the common case.
*   **Two levels (e.g.,** **product\_line.products****):** Acceptable for most use cases. Response payloads grow proportionally.
*   **Three or more levels:** Possible but risky. Response sizes balloon, latency increases, and you approach the API's response size limits. If you need deeply nested data, consider restructuring your content model or making separate targeted queries.

flowchart TD
    P\[Product\] -->|depth 1| PL\[Product Line\]
    P -->|depth 1| C\[Category\]
    PL -->|depth 2| P2\[Other Products\]
    P2 -->|depth 3| C2\[Their Categories\]
    style P2 fill:#fff3cd
    style C2 fill:#f8d7da

Depth 1 (green) is standard. Depth 2 (yellow) is acceptable. Depth 3+ (red) risks payload bloat.

Contentstack's REST API supports include depth through dot notation. There is no explicit "depth" integer parameter - you specify each path you need. This gives you fine-grained control over which branches of the reference tree get resolved.

A common anti-pattern is including everything "just in case." Each unnecessary include adds latency and payload bytes. Only include references that the current view actually renders.

### The include\_all shorthand

For page rendering where you need all references resolved, the SDK supports a convenient shorthand via addParams():

const pageQuery = stack.contentType("page").entry();

pageQuery.addParams({ include\_all: true });
pageQuery.addParams({ include\_all\_depth: 2 });

const result = await pageQuery
  .query()
  .where("url", QueryOperation.EQUALS, "/products/digital-dawn")
  .find();

The include\_all parameter resolves all reference fields on the entry, and include\_all\_depth controls how many levels deep to resolve (default is 1). This is the pattern used in the [kickstart-veda reference application](https://github.com/contentstack/kickstart-veda) for page-level queries where you need the full content tree.

The trade-off is payload size: include\_all resolves every reference field, even ones your page does not render. For listing pages where you only need one or two reference fields, explicit .includeReference() calls are more efficient. For detail pages that render most of the entry's data, include\_all with a depth of 2 is a practical default.

## Localized content retrieval

Contentstack supports multi-language content through its localization system. Each stack has a master locale (typically en-us), and you can create additional locales organized in a hierarchy. Content editors can localize entries per locale, and unlocalized fields fall back to the parent locale.

### The locale parameter

To fetch content in a specific locale, pass the locale parameter.

**REST API:**

GET /v3/content\_types/product/entries?environment=production&locale=fr-fr

**SDK:**

async function getProductsInFrench() {
  const query = stack.contentType("product").entry().query();
  const result = await query.locale("fr-fr").find();
  return result.entries;
}

The SDK uses the .locale() method, which maps to the locale query parameter in REST. When you specify a locale, the API returns entries in that locale. Fields that the editor has translated appear in the target language. Fields that have not been translated may appear empty or may fall back, depending on fallback configuration.

### Fallback language behavior

Contentstack supports one level of fallback per locale. When creating a locale in the stack settings, you specify a fallback locale. For example:

*   fr-fr falls back to fr
*   fr falls back to en-us (the master locale)
*   de-at falls back to de-de

When an entry field has not been localized for the requested locale, the fallback determines what happens. However, fallback behavior is not automatic in API responses by default. You'll want to explicitly request it.

### The include\_fallback parameter

To activate fallback resolution in your API responses, include the include\_fallback parameter:

**REST API:**

GET /v3/content\_types/product/entries?environment=production&locale=fr-ca&include\_fallback=true

**SDK:**

async function getProductsWithFallback(locale: string) {
  const query = stack.contentType("product").entry().query();
  const result = await query
    .locale(locale)
    .includeFallback()
    .find();

  return result.entries;
}

// Request French Canadian; unlocalised fields fall back to fr, then en-us
const products = await getProductsWithFallback("fr-ca");

Without include\_fallback, if a product's description field has not been localized into fr-ca, that field may come back as empty or null. With include\_fallback, the API walks the fallback chain: it checks fr-ca, then falls back to the parent locale (e.g., fr), and finally to the master locale (en-us).

**Tip:** This matters most for sites that are partially localized. A product might have its title translated but its short\_description still in English. With fallback enabled, visitors see the French title and the English description rather than a blank description section.

### The publish\_fallback entry field

When fallback resolves, the API includes metadata about which locale the content actually came from. Look for the publish\_details object on the entry, which indicates the locale in which the entry was published. This lets your frontend display locale indicators or "content not yet translated" notices.

## Combining references and localization

The most common production scenario combines both: you need referenced entries resolved, and you need localized content. Both parameters work together smoothly in a single request.

**REST API:**

GET /v3/content\_types/product/entries?environment=production&locale=fr-fr&include\_fallback=true&include\[\]=category&include\[\]=product\_line

**SDK:**

async function getLocalizedProductWithDetails(slug: string, locale: string) {
  const query = stack.contentType("product").entry().query();

  const result = await query
    .equalTo("url", \`/products/digital-dawn/${slug}\`)
    .locale(locale)
    .includeFallback()
    .includeReference("category")
    .includeReference("product\_line")
    .find();

  const product = result.entries\[0\];
  if (!product) return null;

  return product;
}

// Fetch French product with resolved category and product line
const product = await getLocalizedProductWithDetails(
  "matrix-link-bracelet",
  "fr-fr"
);

console.log(product.title); // "Bracelet Maillon Matrice" (if localized)
product.category.forEach((cat) => {
  console.log(\`${cat.title} - ${cat.url}\`);
  // French or English fallback
});

When references and locale are combined, the API resolves referenced entries in the same locale. If the category "Bracelets" has a French localization, the included entry returns the French version. If it does not, and include\_fallback is set, the fallback chain applies to the referenced entries as well.

### Locale consistency across references

One subtlety to be aware of: referenced entries follow the same locale resolution as the parent entry. If you request locale=fr-fr on a product, the included categories and product lines are also resolved in fr-fr. You do not need to specify the locale separately for each reference.

However, if a referenced entry does not exist in the requested locale and has no fallback, it may be excluded from the response entirely. Test your locale coverage across content types, especially for reference-heavy pages. A product page that shows category and product line in English but missing in French (because they were never localized) creates a confusing experience.

## Fetching a single localized entry by UID

When fetching a specific entry by UID, you can combine locale and reference includes on the single-entry fetch as well:

async function getLocalizedEntry(uid: string, locale: string) {
  const entry = await stack
    .contentType("product")
    .entry(uid)
    .includeReference("category")
    .includeReference("product\_line")
    .locale(locale)
    .includeFallback()
    .fetch();

  return entry;
}

This maps to the REST call:

GET /v3/content\_types/product/entries/blt\_matrix\_link\_001?environment=production&locale=fr-fr&include\_fallback=true&include\[\]=category&include\[\]=product\_line

## Common mistakes with references and localization

**Including the content type UID instead of the field UID:** The include\[\] parameter takes the reference _field_ UID from the parent content type, not the _content type_ UID of the target. include\[\]=category is correct for a field named category; include\[\]=categories would be wrong if the field UID is category.

> **Common pitfall:**
> 
> Omitting include\_fallback on a partially localized stack causes blank fields wherever translation is incomplete -- visitors see missing content instead of the parent-locale fallback.

**Assuming all reference entries exist in all locales:** If category entries are only created in English, requesting locale=ja-jp without fallback returns categories with empty fields or missing entries. Audit locale coverage for referenced content types.

**Over-including nested references:** Including product\_line.products.category resolves three levels deep. Every level multiplies the response payload. Include only what the current page renders.

**Not testing fallback chains:** A locale with a misconfigured fallback parent silently returns empty fields. Verify your locale hierarchy in Settings > Languages.

## Exercise: fetch a product with two levels of references in a specific locale

Build a function that:

1.  Queries the product content type by URL slug.
2.  Resolves the product\_line reference and the nested product\_line.products reference (two levels).
3.  Also resolves the category reference (one level).
4.  Requests locale fr-fr with fallback enabled.
5.  Logs the product title, the product line name, and each related product in the line.
6.  Handles the case where the product does not exist in the requested locale.

Test with a Veda product that has partial French localization - some fields translated, others falling back to English.

#### Key takeaways

- Connect **References, includes, and localized content retrieval** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

## Supplement for indexing

### Content summary

References, includes, and localized content retrieval. References, includes, and localized content retrieval TL;DR Use includeReference() (or include\ \ in REST) with the reference field UID to resolve related entries in a single API call instead of making N+1 separate requests. Always enable include\ fallback on partially localized stacks so visitors see parent-locale content instead of blank fields for untranslated entries. Limit include depth to what the current view actually renders -- each additional level multiplies response payload and latency. Content in Contentstack rarely lives in isolation. A product entry references its category and product line. A page references its components. Understanding how references resolve at the API level

### Retrieval tags

- References
- includes
- and
- localized
- content
- retrieval
- apis-and-developer-tooling
- lesson 09
- References, includes, and localized content retrieval
- apis-and-developer-tooling lesson

### Indexing notes

Index this lesson as a primary chunk tagged with lesson_id "09" and topics: [References, includes, and, localized, content, retrieval].
Parent course slug: apis-and-developer-tooling. Use asset_references URLs as thumbnail hints in search results when present.
Never surface LMS quiz content or assessment answers from this file.

### Asset references

_No image or video thumbnail URLs were extracted._

### External links

| Label | URL |
| --- | --- |
| Contentstack Academy home | `https://www.contentstack.com/academy/` |
| Training instance setup | `https://www.contentstack.com/academy/training-instance` |
| Academy playground (GitHub) | `https://github.com/contentstack/contentstack-academy-playground` |
| Contentstack documentation | `https://www.contentstack.com/docs/` |
| kickstart-veda reference application | `https://github.com/contentstack/kickstart-veda` |
