Skip to content

Strapi API Parameters — Populate, Fields, Sort, Filters, Locale, and PublicationState

DodaTech Updated 2026-06-28 8 min read

In this tutorial, you will master Strapi's API query parameters — the tools that let you control exactly what data the API returns, including which relations to include, which fields to select, how to sort and filter, and how to handle localization and publication state.

What You'll Learn

  • How to use the populate parameter at multiple depth levels
  • How to select specific fields with the fields parameter
  • How to combine multiple parameters in a single request
  • How the locale parameter works with content translation
  • How publicationState controls draft/preview access
  • How to construct complex query URLs with multiple parameters

Why It Matters

The difference between a slow, bloated API and a fast, focused one is how well you use query parameters. Fetching all fields and all relations for a list page that only needs titles and IDs wastes bandwidth and processing time. Mastering API parameters lets you write frontend code that is fast, efficient, and cost-effective.

Real-World Use

A mobile app displays a list of 20 products. Each item only needs the product name, price, and thumbnail image. Using fields to request only name and price, and populate to include only the thumbnail image, reduces the API response from 50KB to 2KB per page. On a mobile network, this means 400ms load times instead of 3 seconds.

Learning Path

flowchart LR
  A["REST API"] --> B["API Parameters
-- You are here"]:::current B --> C["GraphQL Setup"] C --> D["API Customization"] D --> E["API Security"] classDef current fill:#4945ff,color:#fff,stroke-width:2px

The Populate Parameter

The populate parameter includes related data in the API response. Without it, relations return empty objects.

// No population — relations are empty
// GET /api/articles
// Response:
{
  "data": [{
    "attributes": {
      "title": "Article 1",
      "author": { "data": null }  // Empty without populate
    }
  }]
}

// Single relation
// GET /api/articles?populate=author
// Response includes author data

// Multiple relations
// GET /api/articles?populate=author,tags,category

Deep population uses bracket syntax:

// Two levels deep
// GET /api/articles?populate[author][populate]=avatar

// Three levels deep
// GET /api/articles?populate[author][populate][articles][populate]=tags

// Mix deep and shallow
// GET /api/articles?populate[author]=avatar&populate=tags

Strapi limits population depth to prevent infinite loops with circular relations. The default max depth is 5 levels.

The Fields Parameter

The fields parameter selects specific attributes to return. The id is always included.

// Select only title and createdAt
// GET /api/articles?fields[0]=title&fields[1]=createdAt

// Response:
{
  "data": [{
    "id": 1,
    "attributes": {
      "title": "Article 1",
      "createdAt": "2026-06-28T..."
    }
  }]
}

You can use fields together with populate:

// Select fields on the main type and populated relations
// GET /api/articles?fields[0]=title&populate[author][fields][0]=name
// Returns articles with only title, and author with only name

The Sort Parameter

Sort controls the order of returned entries.

// Single field ascending
// GET /api/articles?sort=title

// Single field descending
// GET /api/articles?sort=title:desc

// Multiple fields (array syntax)
// GET /api/articles?sort[0]=createdAt:desc&sort[1]=title:asc

// Sort by nested relation fields
// GET /api/articles?populate=author&sort=author.name:asc

When sorting by multiple fields, entries with equal values in the first sort field are ordered by the second sort field.

The Filters Parameter

Filters query content based on conditions. The syntax uses operators like $eq, $ne, $gt, $lt, $in, $containsi, etc.

// Equality
// GET /api/articles?filters[title]=ExactMatch
// GET /api/articles?filters[title][$eq]=ExactMatch

// Greater than / less than
// GET /api/articles?filters[views][$gte]=100
// GET /api/articles?filters[price][$lt]=50.00

// String matching
// GET /api/articles?filters[title][$containsi]=strapi
// GET /api/articles?filters[title][$startsWith]=How

// Array membership
// GET /api/articles?filters[id][$in]=1,3,5
// GET /api/articles?filters[status][$notIn]=draft,archived

// Null checks
// GET /api/articles?filters[author][$null]=true
// GET /api/articles?filters[author][$notNull]=true

// Date range
// GET /api/articles?filters[createdAt][$gte]=2026-01-01&filters[createdAt][$lte]=2026-06-30

Combine filters for AND logic:

// AND: title contains "guide" AND views >= 100
// GET /api/articles?filters[title][$containsi]=guide&filters[views][$gte]=100

Use $or for OR logic:

// OR: title contains "guide" OR title contains "tutorial"
// GET /api/articles?filters[$or][0][title][$containsi]=guide&filters[$or][1][title][$containsi]=tutorial

Filter on relation fields:

// Filter by author name
// GET /api/articles?filters[author][name][$eq]=Alice

// Filter by category slug
// GET /api/articles?filters[category][slug][$eq]=javascript

The Locale Parameter

When the i18n plugin is enabled, the locale parameter controls which language version of the content to return.

// Get content in English
// GET /api/articles?locale=en

// Get content in French
// GET /api/articles?locale=fr

// Get all localizations of an entry
// GET /api/articles?locale=all
// Returns entries in all available locales

// Get content in the default locale
// GET /api/articles?locale=en (where en is the default)
// If locale is omitted, the default locale is used

When using locale, Strapi returns the content for the requested locale. If the content does not exist in that locale, Strapi's behavior depends on the i18n configuration. By default, it falls back to the default locale.

The PublicationState Parameter

The publicationState parameter controls whether draft entries are included.

// Published only (default)
// GET /api/articles?publicationState=live

// Preview (includes drafts, requires auth)
// GET /api/articles?publicationState=preview

// All entries (includes drafts and published, requires auth)
// GET /api/articles?publicationState=all

Without authentication, preview and all return the same as live. You need a valid JWT or API token with appropriate permissions to see draft content.

Combining Multiple Parameters

The real power comes from combining parameters:

// Full-featured query
GET /api/articles?
  populate[author][fields][0]=name&
  populate[author][fields][1]=avatar&
  populate=tags&
  fields[0]=title&
  fields[1]=content&
  sort[0]=createdAt:desc&
  pagination[page]=1&
  pagination[pageSize]=10&
  filters[category][slug][$eq]=javascript&
  filters[author][name][$containsi]=alice&
  locale=en&
  publicationState=live

// This query:
// - Returns articles in English
// - Only published articles
// - From the JavaScript category
// - By authors with "alice" in their name
// - Sorted by newest first
// - Page 1, 10 per page
// - With only title and content fields
// - Including author name/avatar and tags

URL Encoding

When building URLs programmatically, remember to encode special characters:

// JavaScript: Use URLSearchParams or encodeURIComponent
const params = new URLSearchParams({
  "populate[author][fields][0]": "name",
  "fields[0]": "title",
  "sort": "createdAt:desc"
});
const url = `http://localhost:1337/api/articles?${params.toString()}`;

// The encoded URL:
// http://localhost:1337/api/articles?populate%5Bauthor%5D%5Bfields%5D%5B0%5D=name&fields%5B0%5D=title&sort=createdAt%3Adesc

Different HTTP clients handle URL encoding differently. Ensure your client properly encodes square brackets and special characters.

Common Mistakes

  1. Not using fields and over-fetching. Frontend list views often only need a few fields. Without fields, the API returns all attributes including large richtext and JSON fields. Always specify fields for list endpoints.

  2. Using populate wildcard in production. ?populate=* loads every relation at every level. On a content type with 5 relations, each with their own relations, this can return thousands of fields. Always specify exact relations.

  3. Building URLs manually with string concatenation. String concatenation for query parameters leads to encoding bugs and malformed URLs. Use URL-building libraries or URLSearchParams.

  4. Forgetting locale for multilingual sites. Without the locale parameter, Strapi returns the default locale. Users of other locales see wrong language content.

  5. Not using filters for pagination efficiency. Fetching all entries and filtering on the frontend is inefficient for large datasets. Always use server-side filters, pagination, and sorting.

Practice Questions

  1. Write a query that returns only the names and emails of users who registered in the last 30 days. Answer: GET /api/users?fields[0]=name&fields[1]=email&filters[createdAt][$gte]=2026-05-28

  2. How do you populate a nested relation two levels deep? Answer: GET /api/articles?populate[author][populate]=profile or using bracket notation ?populate[author][populate][0]=profile.

  3. What happens when you use publicationState=preview without authentication? Answer: It returns the same as publicationState=live (published entries only). Authentication is required to see drafts.

  4. Challenge: Write a JavaScript async function that builds and executes a complex Strapi API query. The function should take parameters for content type name, fields, populate, filters, sort, pagination, locale, and publication state, build the URL safely using URLSearchParams, execute the fetch, and return the parsed data. Include error handling for network errors and API error responses.

FAQ

Can I use multiple locale values in one request?

No, each request supports one locale value or all. To get content in multiple specific locales, make separate requests for each locale or use locale=all and filter on the frontend.

What is the difference between $containsi and $contains?

$containsi is case-insensitive. $contains is case-sensitive. Use $containsi for user-facing search that should match regardless of capitalization.

How deep can population go?

The default maximum population depth is 5 levels. You can change this in the Strapi server configuration. Deeper population means more database queries and slower responses.

Do filters work on component fields?

Yes, you can filter on component fields using the dot notation path. For example, filters[seo][meta_title][$containsi]=strapi filters by a component field.

Can I use parameters with GraphQL queries?

Yes, GraphQL supports the same filtering, sorting, and pagination concepts through query arguments. The parameter names and syntax differ but the capabilities are equivalent.

Mini Project

Your task: Create a parameter-optimized API integration.

  1. Create at least 20 articles across 3 categories with 5 different authors and various tags.
  2. Build the following API queries and compare the response sizes:
    • Full response without parameters
    • Response with only title and author name fields
    • Response with pagination (5 per page)
    • Response filtered to a specific category
    • Response sorted by views descending
  3. Measure the response size of each query using curl with -w "%{size_download}".
  4. Document the size difference between the most and least efficient query.

What's Next

Now that you master API parameters, proceed to GraphQL Setup to learn how to install and use Strapi's Graphql plugin for flexible querying. After that, explore API Customization for custom controllers and routes.

Related lessons:

  • GraphQL — Alternative querying approach
  • REST API — Foundation for parameters
  • Node.js — How Strapi processes query parameters

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro