JSON:API basics
The JSON:API module turns every content entity type on the site into an HTTP resource that follows the JSON:API specification. This page covers the endpoint layout and the four query features you reach for first: sparse fieldsets, filtering, sorting, and pagination.
Read content from a Drupal site over HTTP with no custom backend code. By the end you can list a collection, fetch one resource by its UUID, trim the payload to the fields you need, and filter, sort, and page through results. JSON:API ships read-only, so everything here works without changing any access setting.
If you only need a single, fixed shape of data and control both ends, a controller returning JSON may fit better. JSON:API is for clients that query the content model themselves; for how it compares with core’s REST module and contrib GraphQL, see Choose your front end.
Prerequisites
Section titled “Prerequisites”- A Drupal 11 site installed per Install Drupal core, with the Article content model described in the next section.
- The JSON:API module installed:
drush pm:install jsonapi(Drush is Drupal’s command-line tool). - A grasp of entities, bundles, and fields, because JSON:API resource types map directly onto them.
- A tool that can send HTTP requests. The examples use
curl.
The content model these pages use
Section titled “The content model these pages use”Every example on the JSON:API pages, and in the Next.js quickstart, reads an article content type with three fields: body (formatted text), field_image (an image file), and field_tags (references to terms in the Tags vocabulary). Authors carry the user_picture image field that Standard adds to user accounts.
From Drupal 11.4 the Standard profile ships no content types, so add the model by applying the recipe core keeps it in:
ddev exec php web/core/scripts/dr recipe:apply web/core/tests/fixtures/recipes/article_tagsThen create three or four articles at /node/add/article, and give at least one of them an image. On Drupal 11.3 and earlier, Standard already created this model; skip the recipe.
The endpoint layout
Section titled “The endpoint layout”Every resource lives under a single base path, /jsonapi, set by the jsonapi.base_path service parameter. Fetch that path to discover the rest:
curl https://my-site.ddev.site/jsonapiThe response is a document whose links member names one URL per resource type on the site. A resource type is one entity type and bundle joined by --: an article node is node--article, a user is user--user, an uploaded file is file--file. The collection URL for articles is therefore:
curl https://my-site.ddev.site/jsonapi/node/articleJSON:API answers with the media type application/vnd.api+json. Send that in an Accept header so the client and server agree on the format:
curl -H 'Accept: application/vnd.api+json' \ https://my-site.ddev.site/jsonapi/node/articleRead a collection
Section titled “Read a collection”A collection response is a JSON document with a top-level data array. Each entry is a resource object carrying a type, an id (the entity UUID), an attributes object (the field values), and a relationships object (references to other resources):
{ "data": [ { "type": "node--article", "id": "9b5...e1", "attributes": { "title": "First post", "created": "2026-01-04T10:00:00+00:00" } } ]}Only entities the requesting user can view appear in the array. Anonymous requests see published content that the anonymous role may view; nothing here exposes data a visitor could not already reach, because every resource passes the entity’s own view access check.
Read a single resource
Section titled “Read a single resource”Append the entity UUID to the collection path to fetch one resource. The data member is now a single object rather than an array:
curl -H 'Accept: application/vnd.api+json' \ https://my-site.ddev.site/jsonapi/node/article/9b5...e1A UUID that does not resolve to an entity returns 404. An entity the user may not view returns 403, carrying the cacheability metadata of that access decision. When the user lacks full view access but may view the entity’s label, the response degrades to a label-only resource object rather than a 403.
Request only the fields you need
Section titled “Request only the fields you need”By default a resource object carries every field the user may view, which is more than most pages render. The fields parameter limits attributes and relationships per resource type. Key it by type name and pass a comma-separated list:
curl -H 'Accept: application/vnd.api+json' \ 'https://my-site.ddev.site/jsonapi/node/article?fields[node--article]=title,created'The response now carries only title and created for each article. Sparse fieldsets cut payload size and, because they shrink the set of fields the server normalizes, response time as well. The client library on the Next.js quickstart page uses this on its listing query.
Filter the collection
Section titled “Filter the collection”The filter parameter narrows a collection to matching entities. The short form takes a field name and a value, which compares for equality:
curl -H 'Accept: application/vnd.api+json' \ 'https://my-site.ddev.site/jsonapi/node/article?filter[status]=1'For any operator other than equality, name the filter and give it path, operator, and value keys. This returns articles created on or after 1 January 2026:
curl -G -H 'Accept: application/vnd.api+json' \ --data-urlencode 'filter[recent][condition][path]=created' \ --data-urlencode 'filter[recent][condition][operator]=>=' \ --data-urlencode 'filter[recent][condition][value]=1767225600' \ https://my-site.ddev.site/jsonapi/node/articleThe created and changed fields store Unix timestamps, and JSON:API compares filter values as given, so pass seconds since the epoch (1767225600 is 2026-01-01 00:00 UTC). Date fields such as a Date and time field store ISO 8601 strings and take values like 2026-01-01. recent is a label you choose; reuse it to group conditions under one filter. The path may walk relationships with dots, so filter[uid.name]=editor matches articles whose author has the username editor. Supported operators include =, <>, >, >=, <, <=, IN, NOT IN, STARTS_WITH, CONTAINS, and ENDS_WITH.
Sort the results
Section titled “Sort the results”The sort parameter orders a collection by one or more fields. A bare field name sorts ascending; a leading - sorts descending. Separate multiple fields with commas, applied left to right:
curl -H 'Accept: application/vnd.api+json' \ 'https://my-site.ddev.site/jsonapi/node/article?sort=-created,title'This returns articles newest first, breaking ties alphabetically by title.
Page through large collections
Section titled “Page through large collections”JSON:API caps every collection at 50 entries per response. Use page[limit] to request fewer and page[offset] to skip ahead:
curl -H 'Accept: application/vnd.api+json' \ 'https://my-site.ddev.site/jsonapi/node/article?page[limit]=10&page[offset]=10'You do not compute offsets by hand in production. Every collection response carries a links member with next, prev, first, and last URLs already built for the current query. Follow links.next until it is absent, which marks the last page.
Verify
Section titled “Verify”Confirm the module answers and respects each parameter:
ddev drush pm:install jsonapicurl -s -H 'Accept: application/vnd.api+json' \ 'https://my-site.ddev.site/jsonapi/node/article?page[limit]=1&fields[node--article]=title' \ | python3 -m json.toolThe output is a JSON:API document whose data array holds at most one article, each object exposing only the title attribute. A links.next member appears when more articles exist.
Variations
Section titled “Variations”- Resolve references and enable writes. Pulling in related resources with
include, and turning onPOST,PATCH, andDELETE, are covered in JSON:API relationships and writes. - Authenticated requests. To read content beyond what the anonymous role can view, the client must authenticate. See Authentication and CORS.
- Cross-origin browser clients. A front end on a different origin needs CORS enabled before any of these requests succeed from the browser. That setup is also on the Authentication and CORS page.
Related
Section titled “Related”- Choose your front end weighs JSON:API against a Drupal-rendered front end.
- Entities, bundles, and fields explains the data model that resource types expose.
- The
JSON:API architecture topicon api.drupal.org documents the module internals.
Was this page helpful?
Drupal is a registered trademark of Dries Buytaert.