Skip to main content

REST API: Population & Field Selection

The REST API by default does not populate any relations, media fields, components, or dynamic zones. Use the populate parameter to populate specific fields and the select parameter to return only specific fields with the query results. Ensure that the find permission is given to the field(s) for the relation(s) you populate.

💡 Tip

Strapi takes advantage of the ability of the qs library to parse nested objects to create more complex queries.

Use qs directly to generate complex queries instead of creating them manually. Examples in this documentation showcase how you can use qs.

You can also use the interactive query builder if you prefer playing with our online tool instead of generating queries with qs on your machine.

Field selection

Queries can accept a fields parameter to select only some fields. By default, only the following types of fields are returned:

  • string types: string, text, richtext, enumeration, email, password, and uid,
  • date types: date, time, datetime, and timestamp,
  • number types: integer, biginteger, float, and decimal,
  • generic types: boolean, array, and JSON.

Field selection does not work on relational, media, component, or dynamic zone fields. To populate these fields, use the populate parameter.

💡 Tip

By default, fields are selected except relations, media, dynamic zones, and components, but you can specify a wildcard * instead of an array.



Example request: Return only title and body fields

GET /api/users?fields[0]=title&fields[1]=body

Example response
{
"data": [
{
"id": 1,
"attributes": {
"title": "test1",
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
}
}
],
"meta": {
// ...
}
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

const qs = require('qs');
const query = qs.stringify(
{
fields: ['title', 'body'],
},
{
encodeValuesOnly: true, // prettify URL
}
);

await request(`/api/users?${query}`);

Population

The REST API by default does not populate any type of fields, so it will not populate relations, media fields, components, or dynamic zones unless you pass a populate parameter to populate various field types:

It is also possible to combine population with multiple operators among various other operators to have much more control over the population.

Caution

The find permission must be enabled for the content-types that are being populated. If a role doesn't have access to a content-type it will not be populated (see User Guide for additional information on how to enable find permissions for content-types).

✏️ Note

It's currently not possible to return just an array of ids with a request.

Relations & Media fields

Queries can accept a populate parameter to explicitly define which fields to populate, with the following syntax option examples.

Populate 1 level for all relations

To populate one-level deep for all relations, use the * wildcard in combination with the populate parameter.

Example with FoodAdvisor:

Without the populate parameter, a GET request to /api/articles to the server included with the FoodAdvisor example application only returns the "first-level" attributes:

Example request

GET /api/articles

Example response
{
"data": [
{
"id": 1,
"attributes": {
"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,
"attributes": {
"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,
"attributes": {
"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,
"attributes": {
"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
}
}
}
}

With the populate=* parameter, a GET request to /api/articles to the server included with the FoodAdvisor example application includes all first-level relations in the response.

Scroll down to see that the response size is much bigger, and note the following example only shows in full what is returned for the first article (id: 1) whereas the example response without the populate parameter showed the full response content for the 4 published articles:


Example request

GET /api/articles?populate=*

Example response
{
"data": [
{
"id": 1,
"attributes": {
"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,
"attributes": {
"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,
"__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,
"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,
"attributes": {
"name": "European",
"slug": "european",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
},
"localizations": {
"data": [
{
"id": 10,
"attributes": {
"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
}
}
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

const qs = require('qs');
const query = qs.stringify(
{
populate: '*',
},
{
encodeValuesOnly: true, // prettify URL
}
);

await request(`/api/articles?${query}`);

Populate 1 level

To populate only specific relations one-level deep, use one of the following method:

  • Use the populate parameter as an array and put the relation name inside.
  • Use the populate parameter as an object (using LHS bracket notation, i.e., with square brackets [])) and put the relation name as a key with one of the following values: true, false, t, f, 1, 0.
Example request: populate categories

GET /api/articles?populate[0]=categories

Example response
{
"data": [
{
"id": 1,
"attributes": {
"title": "Test Article",
// ...
"categories": {
"data": [
{
"id": 1,
"attributes": {
"name": "Food"
// ...
}
}
]
}
}
}
],
"meta": {
// ...
}
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

// Array method
const qs = require('qs');
const query = qs.stringify(
{
populate: ['categories'],
},
{
encodeValuesOnly: true, // prettify URL
}
);
await request(`/api/articles?${query}`);
// Object method
const qs = require('qs');
const query = qs.stringify(
{
populate: {
categories: true
}
},
{
encodeValuesOnly: true // prettify URL
}
);

await request(`/api/articles?${query}`);

Populate 2 levels

To populate specific relations, one or several levels deep, use the LHS bracket notation (i.e., with square brackets []) for fields names in combination with the populate parameter.


✏️ Note

There is no limit on the number of levels that can be populated. However, the more nested populates there are, the more the request will take time to be performed.

Example request: populate author and author.company

GET /api/articles?populate[author][populate][0]=company

Example response
{
"data": [
{
"id": 1,
"attributes": {
"title": "Test Article",
// ...
"author": {
"data": {
"id": 1,
"attributes": {
"name": "Kai Doe",
// ...
"company": {
"data": {
"id": 1,
"attributes": {
"name": "Strapi"
// ...
}
}
}
}
}
}
}
}
],
"meta": {
// ...
}
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

const qs = require('qs');
const query = qs.stringify(
{
populate: {
author: {
populate: ['company'],
},
},
},
{
encodeValuesOnly: true, // prettify URL
}
);
await request(`/api/articles?${query}`);

Components & Dynamic Zones

The populate parameter is used to explicitly define which Dynamic zones, components, and nested components to populate.

Example: Deeply populate a 2-level component & media

To populate a 2-level component & its media, you need to explicitly ask for each element with the populate parameter, passing all elements in an array.


💡 Tip

The easiest way to build complex queries with multiple-level population is to use our interactive query builder tool.

Example request

GET /api/articles?populate[0]=seoData&populate[1]=seoData.sharedImage&populate[2]=seoData.sharedImage.media

Example response
{
"data": [
{
"id": 1,
"attributes": {
"title": "Test Article",
// ...
"seoData": {
"id": 1,
"metaTitle": "Test Article",
// ...
"sharedImage": {
"id": 1,
"alt": "starSky",
"media": {
"data": [
{
"id": 1,
"attributes": {
"name": "17520.jpg",
"formats": {
// ...
},
// ...
}
}
]
}
}
}
}
}
],
"meta": {
// ...
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

const qs = require('qs');
const query = qs.stringify(
{
populate: [
'seoData',
'seoData.sharedImage',
'seoData.sharedImage.media',
],
},
{
encodeValuesOnly: true, // prettify URL
}
);

await request(`/api/articles?${query}`);

Example: Deeply populate a dynamic zone with 2 components

Dynamic zones are highly dynamic content structures by essence. When populating dynamic zones, you can choose between a shared population strategy or a detailed population strategy.

In a shared population strategy, apply a unique behavior for all the dynamic zone's components.

Example request for shared populate strategy

GET /api/articles?populate[testDZ][populate]=*

Example response for shared populate strategy
{
"data": [
{
"id": 1,
"attributes": {
"testString": "test1",
// ...
"testDZ": [
{
"id": 3,
"__component": "test.test-compo",
"testString": "test1",
"testNestedCompo": {
"id": 3,
"testNestedString": "testNested1"
},
"otherField": "test"
},
{
"id": 1,
"__component": "test.test-compo2",
"testInt": 1,
"otherField": "test"
}
]
}
}
],
"meta": {
// ...
}
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

const qs = require('qs');
const query = qs.stringify(
{
populate: {
testDZ: {
populate: '*',
},
},
},
{
encodeValuesOnly: true, // prettify URL
}
);

await request(`/api/articles?${query}`);

With the detailed population strategy, define per-component populate queries using the on property.

Example request for detailed populate strategy

GET /api/articles?populate[testDz][on][test.test-compo][fields][0]=testString&populate[testDz][on][test.test-compo][populate]=*&populate[testDz][on][test.test-compo2][fields][0]=testInt

Example response for detailed populate strategy
{
"data": [
{
"id": 1,
"attributes": {
"testString": "test1",
// ...
"testDZ": [
{
"id": 3,
"__component": "test.test-compo",
"testString": "test1",
"testNestedCompo": {
"testNestedString": "testNested1"
}
},
{
"id": 1,
"__component": "test.test-compo2",
"testInt": 1
}
]
}
}
],
"meta": {
// ...
}
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

const qs = require('qs');
const query = qs.stringify(
{
populate: {
testDz: {
on: {
'test.test-compo': {
fields: ['testString'],
populate: '*',
},
'test.test-compo2': {
fields: ['testInt'],
},
},
},
},
},
{
encodeValuesOnly: true, // prettify URL
}
);

await request(`/api/articles?${query}`);

Combining Population with other operators

By utilizing the populate operator it is possible to combine other operators such as field selection, filters, and sort in the population queries.

Caution

The population and pagination operators cannot be combined.

Populate with field selection

fields and populate can be combined.

Example request

GET /api/articles?fields[0]=title&fields[1]=slug&populate[headerImage][fields][0]=name&populate[headerImage][fields][1]=url

Example response
{
"data": [
{
"id": 1,
"attributes": {
"title": "Test Article",
"slug": "test-article",
"headerImage": {
"data": {
"id": 1,
"attributes": {
"name": "17520.jpg",
"url": "/uploads/17520_73c601c014.jpg"
}
}
}
}
}
],
"meta": {
// ...
}
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

const qs = require('qs');
const query = qs.stringify(
{
fields: ['title', 'slug'],
populate: {
headerImage: {
fields: ['name', 'url'],
},
},
},
{
encodeValuesOnly: true, // prettify URL
}
);

await request(`/api/articles?${query}`);

Populate with filtering

filters and populate can be combined.

Example request

GET /api/articles?populate[categories][sort][0]=name%3Aasc&populate[categories][filters][name][$eq]=Cars

Example response
{
"data": [
{
"id": 1,
"attributes": {
"title": "Test Article",
// ...
"categories": {
"data": [
{
"id": 2,
"attributes": {
"name": "Cars"
// ...
}
}
]
}
}
}
],
"meta": {
// ...
}
}

JavaScript query (built with the qs library):

The query URL above was built using the qs library. qs can be run locally on your machine, as shown in the following code example, or you can use our interactive query builder online tool.

const qs = require('qs');
const query = qs.stringify(
{
populate: {
categories: {
sort: ['name:asc'],
filters: {
name: {
$eq: 'Cars',
},
},
},
},
},
{
encodeValuesOnly: true, // prettify URL
}
);

await request(`/api/articles?${query}`);