🧠 Understanding the populate
parameter for the REST API
The content of this page might not be fully up-to-date with Strapi 5 yet.
The content of this page might not be fully up-to-date with Strapi 5 yet:
- All the conceptual information and explanations are correct and up-to-date.
- However, in the examples, the response content might be slightly different.
Examples will be fully up-to-date after the Strapi 5.0.0 (stable version) release and as soon as the FoodAdvisor example application is upgraded to Strapi 5.
However, having slightly different response examples should not prevent you from grasping the essential concepts taught in this page.
When querying content-types with Strapi's REST API, by default, responses only include top-level fields and do not include any relations, media fields, components, or dynamic zones.
Populating in the context of the Strapi REST API means including additional content with your response by returning more fields than the ones returned by default. You use the populate
parameter to achieve this.
Throughout this guide, examples are built with real data queried from the server included with the FoodAdvisor example application. To test examples by yourself, setup FoodAdvisor, start the server in the /api/
folder, and ensure that proper find
permissions are given for the queried content-types before sending your queries.
The present guide will cover detailed explanations for the following use cases:
- populate all fields and relations, 1 level deep,
- populate some fields and relations, 1 level deep,
- populate some fields and relations, several levels deep,
- populate components,
- populate dynamic zones.
Populating several levels deep is often called "deep populate".
In addition to the various ways of using the populate
parameter in your queries, you can also build a custom controller as a workaround to populate creator fields (e.g., createdBy
and updatedBy
). This is explained in the dedicated How to populate creator fields guide.
Populate all relations and fields, 1 level deep
You can return all relations, media fields, components and dynamic zones with a single query. For relations, this will only work 1 level deep, to prevent performance issues and long response times.
To populate everything 1 level deep, add the populate=*
parameter to your query.
The following diagram compares data returned by the FoodAdvisor example application with and without populating everything 1 level deep:
Let's compare and explain what happens with and without this query parameter:
Example: Without populate
Without the populate parameter, a GET
request to /api/articles
only returns the default attributes and does not return any media fields, relations, components or dynamic zones.
The following example is the full response for all 4 entries from the articles
content-types.
Notice how the response only includes the title
, slug
, createdAt
, updatedAt
, publishedAt
, and locale
fields, and the field content of the article as handled by the CKEditor plugin (ckeditor_content
, truncated for brevity):
GET /api/articles
{
"data": [
{
"id": 1,
"documentId": "t3q2i3v1z2j7o8p6d0o4xxg",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": // truncated content
},
{
"id": 2,
"documentId": "k2r5l0i9g3u2j3b4p7f0sed",
"title": "What are chinese hamburgers and why aren't you eating them?",
"slug": "what-are-chinese-hamburgers-and-why-aren-t-you-eating-them",
"createdAt": "2021-11-11T13:33:19.948Z",
"updatedAt": "2023-06-01T14:32:50.984Z",
"publishedAt": "2022-09-22T12:36:48.312Z",
"locale": "en",
"ckeditor_content": // truncated content
},
{
"id": 3,
"documentId": "k6m6l9q0n6v9z2m3i0z5jah"
"title": "7 Places worth visiting for the food alone",
"slug": "7-places-worth-visiting-for-the-food-alone",
"createdAt": "2021-11-12T13:33:19.948Z",
"updatedAt": "2023-06-02T11:30:00.075Z",
"publishedAt": "2023-06-02T11:30:00.075Z",
"locale": "en",
"ckeditor_content": // truncated content
},
{
"id": 4,
"documentId": "d5m4b6z6g5d9e3v1k9n5gbn",
"title": "If you don't finish your plate in these countries, you might offend someone",
"slug": "if-you-don-t-finish-your-plate-in-these-countries-you-might-offend-someone",
"createdAt": "2021-11-15T13:33:19.948Z",
"updatedAt": "2023-06-02T10:59:35.148Z",
"publishedAt": "2022-09-22T12:35:53.899Z",
"locale": "en",
"ckeditor_content": // truncated content
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}
Example: With populate=*
With the populate=*
parameter, a GET
request to /api/articles
also returns all media fields, first-level relations, components and dynamic zones.
The following example is the full response for the first of all 4 entries from the articles
content-types (the data from articles with ids 2, 3, and 4 is truncated for brevity).
Scroll down to see that the response size is much bigger than without populate. The response now includes additional fields (see highlighted lines) such as:
- the
image
media field (which stores all information about the article cover, including all its different formats), - the first-level fields of the
blocks
dynamic zone and theseo
component, - the
category
relation and its fields, - and even some information about the articles translated in other languages, as shown by the
localizations
object.
To populate deeply nested components, see the populate components section.
GET /api/articles?populate=*
{
"data": [
{
"id": 1,
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": // truncated content
"image": {
"data": {
"id": 12,
"documentId": "o5d4b0l4p8l4o4k5n1l3rxa",
"name": "Basque dish",
"alternativeText": "Basque dish",
"caption": "Basque dish",
"width": 758,
"height": 506,
"formats": {
"thumbnail": {
"name": "thumbnail_https://4d40-2a01-cb00-c8b-1800-7cbb-7da-ea9d-2011.ngrok.io/uploads/basque_cuisine_17fa4567e0.jpeg",
"hash": "thumbnail_basque_cuisine_17fa4567e0_f033424240",
"ext": ".jpeg",
"mime": "image/jpeg",
"width": 234,
"height": 156,
"size": 11.31,
"path": null,
"url": "/uploads/thumbnail_basque_cuisine_17fa4567e0_f033424240.jpeg"
},
"medium": {
"name": "medium_https://4d40-2a01-cb00-c8b-1800-7cbb-7da-ea9d-2011.ngrok.io/uploads/basque_cuisine_17fa4567e0.jpeg",
"hash": "medium_basque_cuisine_17fa4567e0_f033424240",
"ext": ".jpeg",
"mime": "image/jpeg",
"width": 750,
"height": 501,
"size": 82.09,
"path": null,
"url": "/uploads/medium_basque_cuisine_17fa4567e0_f033424240.jpeg"
},
"small": {
"name": "small_https://4d40-2a01-cb00-c8b-1800-7cbb-7da-ea9d-2011.ngrok.io/uploads/basque_cuisine_17fa4567e0.jpeg",
"hash": "small_basque_cuisine_17fa4567e0_f033424240",
"ext": ".jpeg",
"mime": "image/jpeg",
"width": 500,
"height": 334,
"size": 41.03,
"path": null,
"url": "/uploads/small_basque_cuisine_17fa4567e0_f033424240.jpeg"
}
},
"hash": "basque_cuisine_17fa4567e0_f033424240",
"ext": ".jpeg",
"mime": "image/jpeg",
"size": 58.209999999999994,
"url": "/uploads/basque_cuisine_17fa4567e0_f033424240.jpeg",
"previewUrl": null,
"provider": "local",
"provider_metadata": null,
"createdAt": "2021-11-23T14:05:33.460Z",
"updatedAt": "2021-11-23T14:05:46.084Z"
}
}
},
"blocks": [
{
"id": 2,
"__component": "blocks.related-articles"
},
{
"id": 2,
"documentId": "w8r5k8o8v0t9l9e0d7y6vco",
"__component": "blocks.cta-command-line",
"theme": "primary",
"title": "Want to give a try to a Strapi starter?",
"text": "❤️",
"commandLine": "git clone https://github.com/strapi/nextjs-corporate-starter.git"
}
],
"seo": {
"id": 1,
"documentId": "h7c8d0u3i3q5v1j3j3r4cxf",
"metaTitle": "Articles - FoodAdvisor",
"metaDescription": "Discover our articles about food, restaurants, bars and more! - FoodAdvisor",
"keywords": "food",
"metaRobots": null,
"structuredData": null,
"metaViewport": null,
"canonicalURL": null
},
"category": {
"data": {
"id": 4,
"documentId": "t1t3d9k6n1k5a6r8l7f8rox",
"name": "European",
"slug": "european",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
},
"localizations": {
"data": [
{
"id": 10,
"documentId": "h7c8d0u3i3q5v1j3j3r4cxf",
"title": "Voici pourquoi il faut essayer la cuisine basque, selon un chef basque",
"slug": "voici-pourquoi-il-faut-essayer-la-cuisine-basque-selon-un-chef-basque",
"createdAt": "2021-11-18T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.606Z",
"publishedAt": "2022-09-22T13:00:00.069Z",
"locale": "fr-FR",
"ckeditor_content": // truncated content
}
]
}
}
},
{
"id": 2,
// truncated content
},
{
"id": 3,
// truncated content
},
{
"id": 4,
// truncated content
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}
Populate specific relations and fields
You can also populate specific relations and fields, by explicitly defining what to populate. This requires that you know the name of fields and relations to populate.
Relations and fields populated this way can be 1 or several levels deep. The following diagram compares data returned by the FoodAdvisor example application when you populate 1 level deep vs. 2 levels deep:
Depending on your data structure, you might get similar data presented in different ways with different queries. For instance, the FoodAdvisor example application includes the article, category, and restaurant content-types that are all in relation to each other in different ways. This means that if you want to get data about the 3 content-types in a single GET request, you have 2 options:
- query articles and populate categories, plus populate the nested relation between categories and restaurants (2 levels deep population)
- query categories and populate both articles and restaurants because categories have a 1st level relation with the 2 other content-types (1 level deep)
The 2 different strategies are illustrated in the following diagram:
Populate as an object vs. populate as an array: Using the interactive query builder
The syntax for advanced query parameters can be quite complex to build manually. We recommend you use our interactive query builder tool to generate the URL.
Using this tool, you will write clean and readable requests in a familiar (JavaScript) format, which should help you understand the differences between different queries and different ways of populating. For instance, populating 2 levels deep implies using populate as an object, while populating several relations 1 level deep implies using populate as an array:
Populate as an object
(to populate 1 relation several levels deep):
{
populate: {
category: {
populate: ['restaurants'],
},
},
}
Populate as an array
(to populate many relations 1 level deep)
{
populate: [
'articles',
'restaurants'
],
}
Populate 1 level deep for specific relations
You can populate specific relations 1 level deep by using the populate parameter as an array.
Since the REST API uses the LHS bracket notation (i.e., with square brackets []
), the parameter syntaxes to populate 1 level deep would look like the following:
How many relations to populate | Syntax example |
---|---|
Only 1 relation | populate[0]=a-relation-name |
Several relations | populate[0]=relation-name&populate[1]=another-relation-name&populate[2]=yet-another-relation-name |
Let's compare and explain what happens with and without populating relations 1 level deep when sending queries to the FoodAdvisor example application:
Example: Without populate
Without the populate parameter, a GET
request to /api/articles
only returns the default attributes.
The following example is the full response for all 4 entries from the articles
content-type.
Notice that the response does not include any media fields, relations, components or dynamic zones:
GET /api/articles
{
"data": [
{
"id": 1,
"documentId": "x2m0d7d9o4m2z3u2r2l9yes",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
},
{
"id": 2,
"documentId": "k6m6l9q0n6v9z2m3i0z5jah",
"title": "What are chinese hamburgers and why aren't you eating them?",
"slug": "what-are-chinese-hamburgers-and-why-aren-t-you-eating-them",
"createdAt": "2021-11-11T13:33:19.948Z",
"updatedAt": "2023-06-01T14:32:50.984Z",
"publishedAt": "2022-09-22T12:36:48.312Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
},
{
"id": 3,
"documentId": "o5d4b0l4p8l4o4k5n1l3rxa",
"title": "7 Places worth visiting for the food alone",
"slug": "7-places-worth-visiting-for-the-food-alone",
"createdAt": "2021-11-12T13:33:19.948Z",
"updatedAt": "2023-06-02T11:30:00.075Z",
"publishedAt": "2023-06-02T11:30:00.075Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
},
{
"id": 4,
"documentId": "t3q2i3v1z2j7o8p6d0o4xxg",
"title": "If you don't finish your plate in these countries, you might offend someone",
"slug": "if-you-don-t-finish-your-plate-in-these-countries-you-might-offend-someone",
"createdAt": "2021-11-15T13:33:19.948Z",
"updatedAt": "2023-06-02T10:59:35.148Z",
"publishedAt": "2022-09-22T12:35:53.899Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}
}
Example: With populate[0]=category
With populate[0]=category
added to the request, we explicitly ask to include some information about category
, which is a relation field that links the articles
and the categories
content-types.
The following example is the full response for all 4 entries from the articles
content-type.
Notice that the response now includes additional data with the category
field for each article (see highlighted lines):
GET /api/articles?populate[0]=category
{
"data": [
{
"id": 1,
"documentId": "w8r5k8o8v0t9l9e0d7y6vco",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "