Connect

Query Parameters

Learn about Directus query parameters - fields, filter, search, sort, limit, offset, page, aggregate, groupBy, deep, alias, and export. Understand how to customize your API requests and retrieve specific data from your collections.

Most Directus API endpoints can use global query parameters to alter the data that is returned.

Fields

Specify which fields are returned. This parameter also supports dot notation to request nested relational fields, and wildcards (*) to include all fields at a specific depth.

GET /items/posts
    ?fields=first_name,last_name,avatar.description
Examples
ValueDescription
first_name,last_nameReturn only the first_name and last_name fields.
title,author.nameReturn title and the related author item's name field.
*Return all fields.
*.*Return all fields and all immediately related fields.
*,images.*Return all fields and all fields within the images relationship.
Wildcards and performance While wildcards are very useful, we recommend only requesting specific fields in production. By only requesting the fields you need, you can speed up the request, and reduce the overall output size.

Many to Any Fields

As Many to Any (M2A) fields have nested data from multiple collections, you are not always able to fetch the same field from every related collection. In M2A fields, you can use the following syntax to specify what fields to fetch from which related nested collection type: ?fields=m2a-field:collection-scope.field

Example
In an posts collection there is a Many to Any field called sections that points to headings, paragraphs, and videos. Different fields should be fetched from each related collection.
GET /items/posts
?fields[]=title
&fields[]=sections.item:headings.title
&fields[]=sections.item:headings.level
&fields[]=sections.item:paragraphs.body
&fields[]=sections.item:videos.source

Filter

Specify which items are returned based on the result of a filter rule.

// There are two available syntax:

GET /items/posts
    ?filter[title][_eq]=Hello

GET /items/posts
    ?filter={ "title": { "_eq": "Hello" }}

Search on all string and text type fields within a collection. It's an easy way to search for an item without creating complex field filters – though it is far less optimized. Related item fields are not included.

GET /items/posts
    ?search=Directus

Sort

What fields to sort results by. Sorting defaults to ascending, but appending a - will reverse this. Fields are prioritized by the order in the parameter. The dot notation is used to sort with values of related fields.

GET /items/posts
    ?sort=sort,-date_created,author.name

Limit

Set the maximum number of items that will be returned. The default limit is set to 100. -1 will return all items.

GET /items/posts
    ?limit=50
Large limits and performance
Depending on the size of your collection, fetching the maximum amount of items may result in degraded performance or timeouts.The maximum number of items that can be requested on the API can be configured using the QUERY_LIMIT_MAX environment variable. This cannot be overridden by changing the value of limit.

Offset

Skip the specified number of items in the response. This parameter can be used for pagination.

GET /items/posts
    ?offset=100

Page

An alternative to offset. Returned values are the value of limit multiplied by page. The first page is 1.

GET /items/posts
    ?page=2

Aggregate

Aggregate functions allow you to perform calculations on a set of values, returning a single result.

FunctionDescription
countCounts how many items there are
countDistinctCounts how many unique items there are
sumAdds together the values in the given field
sumDistinctAdds together the unique values in the given field
avgGet the average value of the given field
avgDistinctGet the average value of the unique values in the given field
minReturn the lowest value in the field
maxReturn the highest value in the field
countAllEquivalent to ?aggregate[count]=* (GraphQL only)
GET /items/posts
    ?aggregate[count]=*

GroupBy

Grouping allows for running aggregate functions based on a shared value, rather than the entire dataset.

You can group by multiple fields simultaneously. Combined with the functions, this allows for aggregate reporting per year-month-date.

GET /items/posts
  ?aggregate[count]=views,comments
  &groupBy[]=author
  &groupBy[]=year(publish_date)

Deep

Deep allows you to set any of the other query parameters (except for Fields and Deep itself) on a nested relational dataset.

The nested query parameters are to be prefixed with an underscore.

// There are two available syntax:

GET /items/posts
    ?deep[translations][_filter][languages_code][_eq]=en-US

GET /items/posts
    ?deep={ "translations": { "_filter": { "languages_code": { "_eq": "en-US" }}}}
Example
Only get 3 related posts, with only the top rated comment nested:
{
    "deep": {
        "related_posts": {
            "_limit": 3,
            "comments": {
                "_sort": "rating",
                "_limit": 1
            }
        }
  }
}

Alias

Rename fields for this request, and fetch the same nested data set multiple times using different filters.

GET /items/posts
    ?alias[all_translations]=translations
    &alias[dutch_translations]=translations
    &deep[dutch_translations][_filter][code][_eq]=nl-NL
Aliases in combination with other features
Aliases support being used in combination with:
  1. functions, e.g. alias[release_year]=year(released)
  2. in the deep query parameter, e.g. deep[author][_alias][birthyear]=year(birthday)
Note that it is not possible to use aliases on relational fields e.g. alias[author_name]=author.name and not possible to have . in the alias name itself e.g. alias[not.possible]=field.

Export

Saves the API response to a file. Valid values are csv, json, xml, yaml.

GET /items/posts
?export=type

Version

Queries a version of a record by version key when content versioning is enabled on a collection. Applies only to single item retrieval.

GET /items/posts/1
?version=v1
GraphQL
query {
  posts_by_id(id: 1, version: "v1") {
    id
  }
}
SDK
import { createDirectus, rest, readItem } from "@directus/sdk";
const directus = createDirectus("https://directus.example.com").with(rest());

const result = await directus.request(
  readItem("posts", {
    version: "v1",
  })
);

VersionRaw

Specifies to return relational delta changes as a detailed output on a version record.

GET /items/posts/1
?version=v1&versionRaw=true
GraphQL
query {
  posts_by_version(id: 1, version: "v1") {
    id
  }
}
SDK
import { createDirectus, rest, readItem } from "@directus/sdk";
const directus = createDirectus("https://directus.example.com").with(rest());

const result = await directus.request(
  readItem("posts", {
    version: "v1",
    versionRaw: true,
  })
);

Functions

Functions accept a field and return a modified value. Functions can be used in any query parameter you'd normally supply a field key, including fields, aggregation, and filters.

The syntax for using a function is function(field).

FunctionDescription
yearExtract the year from a datetime/date/timestamp field
monthExtract the month from a datetime/date/timestamp field
weekExtract the week from a datetime/date/timestamp field
dayExtract the day from a datetime/date/timestamp field
weekdayExtract the weekday from a datetime/date/timestamp field
hourExtract the hour from a datetime/date/timestamp field
minuteExtract the minute from a datetime/date/timestamp field
secondExtract the second from a datetime/date/timestamp field
countExtract the number of items from a JSON array or relational field
jsonExtract a specific value from a JSON field using path notation
GET /items/posts
    ?filter[year(date_published)][_eq]=1968

The json(field, path) Function

The json(field, path) function extracts a specific value from a JSON field and returns it as a separate field in the query response. It is used in the fields query parameter alongside regular field names and other field functions.

Supported Paramaters the json(field, path) function is currently only supported for use in the fields query parameter.

Syntax

json(field, path)
  • field — the name of a JSON column in the collection (or a relational path to one, see Relational Queries).
  • path — a dot-and-bracket notation path to the value you want to extract from within the JSON document.
Both arguments are required and separated by a comma.

Path Notation

Paths use dot notation for object keys and bracket notation for array indices.
PatternExampleMeaning
keycolorTop-level key
a.b.csettings.theme.colorNested keys
[n]tags[0]Array element at index n
a[n].bitems[0].nameMixed object/array access
Examples:
json(metadata, color)                   → top-level key
json(metadata, settings.theme)          → nested object
json(data, items[0].name)               → array element property
json(data, [0])                         → first element of a top-level array

Response Format

Extracted values are returned as additional fields on each item using auto-generated aliases. The alias follows the pattern:
{field}_{path}_json
Special characters in the path ([, ], .) are replaced with underscores. For example:
Request fieldResponse key
json(metadata, color)metadata_color_json
json(metadata, settings.priority)metadata_settings_priority_json
json(data, items[0].name)data_items_0_name_json

Example Request and Response

GET /items/articles?fields=id,title,json(metadata, color)&sort=title
{
  "data": [
    {
      "id": 1,
      "title": "An Article",
      "metadata_color_json": "blue"
    }
  ]
}

Relational Queries

json(field, path) can traverse relational fields to extract JSON values from related items. The relational path goes inside the first argument, before the JSON field name.

Many-to-One (M2O)

json(relation.json_field, path)
The extracted value is returned nested under the relational key in the response, alongside any other requested fields from that relation.
GET /items/articles?fields=id,title,category_id.name,json(category_id.metadata, color)
{
  "data": [
    {
      "id": 1,
      "title": "An Article",
      "category_id": {
        "name": "Tech",
        "metadata_color_json": "blue"
      }
    }
  ]
}
Multiple json(field, path) extractions from the same relation are grouped under the same relational key:
GET /items/articles?fields=id,json(category_id.metadata, color),json(category_id.metadata, icon)
{
  "data": [
    {
      "category_id": {
        "metadata_color_json": "blue",
        "metadata_icon_json": "laptop"
      }
    }
  ]
}

One-to-Many (O2M)

For O2M relations, each related item returns its own extracted value. The response is an array of objects, each containing the extracted key.
GET /items/articles/1?fields=id,json(comments.data, type)
{
  "data": {
    "id": 1,
    "comments": [
      { "data_type_json": "review" },
      { "data_type_json": "feedback" },
      { "data_type_json": "question" }
    ]
  }
}

Many-to-Any (M2A)

For M2A relations, use the standard Directus collection scope syntax inside the first argument:
json(relation.item:collection_name.json_field, path)
GET /items/shapes/1?fields=id,json(children.item:circles.metadata, color)

Relational Depth Limit

Directus enforces a maximum relational depth (MAX_RELATIONAL_DEPTH, default 10). For json(), only the first argument (the field path) counts toward this limit — the JSON path in the second argument is excluded.
json(category_id.metadata, a.b.c.d.e)
This has a relational depth of 2 (category_id + metadata), regardless of how many segments are in the JSON path a.b.c.d.e.Exceeding the relational depth returns a 400 Invalid query. Max relational depth exceeded. error.

JSON Path Depth Limit

The JSON path (second argument) also has its own configurable limit:
MAX_JSON_QUERY_DEPTH=10  # default
Depth is counted by the number of . and [ characters in the normalized path. A path like a.b.c.d.e.f.g.h.i.j has depth 10 and is allowed by default; adding one more segment exceeds the limit.Exceeding this limit returns an error.

Unsupported Path Expressions

The following path syntaxes are not supported and will return a 400 error:| Expression | Example | |---|---|---| | Empty brackets (wildcard) | items[] | | [*] wildcard | items[*].name | | * glob | items.* | | JSONPath predicates | items[?(@.price > 10)] | | @ current node | @.name | | $ root | $.name |

Object Keys with Special Characters

The json(field, path) path syntax uses . as a separator between key segments. There is no escape mechanism for object keys that themselves contain dots, spaces, or other special characters. For example, if your JSON has a key "first.name", there is no way to express that in the path — json(data, first.name) would be interpreted as nested access to key first, then key name.Similarly, because MySQL and MariaDB path conversion uses dot-notation ($.key.subkey), keys containing characters that are special in that context (e.g., spaces) may not be reachable. PostgreSQL's parameterized ->? approach is more permissive for unusual key names, but the input path format still does not provide an escaping mechanism.

Database-Specific Exceptions

SQLite
  • SQLite can return 0/1 isntead of boolean values.
MSSQL
  • JSON_VALUE in MSSQL always returns scalar values as strings (NVARCHAR), even when the original JSON value is a number or boolean. For example, a JSON integer 42 will be returned as the string "42". Your application should perform type coercion as needed.
Oracle
  • Similar to MSSQL will also return scalar values as strings, regardless of the original JSON type (number, boolean, etc.). A JSON number 3.14 will be returned as "3.14".

When backlink is set to false, the API will exclude reverse relations during *.* wildcard field expansion to prevent circular references and reduce duplicate data in responses.

The backlink parameter defaults to true, so you need to explicitly set it to false to enable the filtering behavior.

Wildcard Only
The backlink parameter only affects *.* wildcard field expansion. Explicitly specified field names are not filtered. For example: fields=author.articles will still include the reverse relation even when backlink=false.
GET /items/posts
    ?fields=*.*.*
    &backlink=false
Example
Red lines mark the response when backlink is set to true while green marks when backlinks is set to false. The articles collection consists of a many-to-one relation to Users called author and a many-to-many relation to Tags called tags.
GET /items/articles?fields=*.*.*&backlink=true / false
{
  "data": [
    {
      "id": 1,
      "title": "My first Article",
      "author": {
        "id": 2,
        "name": "Nils",
        "articles": [
          {             "id": 1,             "title": "My first Article",             "author": {               "id": 2,               "name": "Nils",               "articles": [1]             },             "tags": [               {                 "id": 3,                 "articles_id": 1,                 "tags_id": 4              }             ]           }           1        ]
      },
      "tags": [
        {
          "id": 3,
          "articles_id": {             "id": 1,             "title": "My first Article",             "author": {               "id": 2,               "name": "Nils",               "articles": [1]             },              "tags": [               {                 "id": 3,                 "articles_id": 1,                 "tags_id": 4              }             ]           },           "articles_id": 1,           "tags_id": {
            "id": 4,
            "tag": "Tag1",
            "articles": [
              {                 "id": 3,                 "articles_id": 1,                 "tags_id": 4              }               3            ]
          }
        }
      ]
    }
  ]
}

Get once-a-month release notes & real‑world code tips...no fluff. 🐰