Documents
document-service
document-service
Type
External
Status
Published
Created
Mar 5, 2026
Updated
Mar 5, 2026

Document Service API#

The Document Service API is built on top of the Query Engine API 2 different back-end APIs allow you to interact with your content:

  • The Query Engine API is the lower-level layer that offers unrestricted access to the database, but is not aware of complex Strapi content structures such as components and dynamic zones.
  • The Document Service API is built on top of the Query Engine and is the recommended way to interact with your content while you are customizing the back end server or developing plugins.
More details can be found in the Content API and backend customization introductions. and is used to perform CRUD (create, retrieve, update, and delete) operations on documents .

The Document Service API also supports counting documents and, if Draft & Publish is enabled on the content-type, performing Strapi-specific operations such as publishing, unpublishing, and discarding drafts.

In Strapi 5, documents are uniquely identified by their documentId at the API level.

documentId explained: Replacing id from Strapi v4

In previous Strapi versions, the concept of id (used both in the Content API and as the database row identifier) was not always stable: a single entry could have multiple versions or localizations, and its numeric identifier id could change in cases such as duplication or import/export operations.

To address this limitation, Strapi 5 introduced documentId, a 24-character alphanumeric string, as a unique and persistent identifier for a content entry, independent of its physical records.

This new identifier is used internally in Strapi 5 to manage relationships, publishing, localization, and version history, as all possible variations of a content entry are now grouped under a single document concept.

As a result, starting with Strapi 5, many APIs and services rely on documentId instead of id to ensure consistency across operations. Some APIs may still return both documentId and id to ease the transition, but using documentId for content queries is strongly recommended, as documentId might be the only identifier used in future Strapi versions.

For more details on the transition from id to documentId, refer to the breaking change page and the migration guide from Entity Service to Document Service API.

:::strapi Entity Service API is deprecated in Strapi 5
The Document Service API replaces the Entity Service API used in Strapi v4 ().

Additional information on how to migrate from the Entity Service API to the Document Service API can be found in the migration reference.
:::

Configuration#

The documents.strictParams option enables strict validation of parameters passed to Document Service methods such as findMany and findOne. Configure it in the API configuration file (./config/api.js or ./config/api.ts). See the API configuration table for details on documents.strictParams.

Document objects#

Document methods return a document object or a list of document objects, which represent a version of a content entry grouped under a stable documentId. Returned objects typically include:

  • documentId: Persistent identifier for the entry across locales and draft/published versions.
  • id: Database identifier for the specific locale/version record.
  • model fields: All fields defined in the content-type schema. Relations, components, and dynamic zones are not populated unless you opt in with populate (see Populating fields) or limit fields with fields (see Selecting fields).
  • metadata: publishedAt, createdAt, updatedAt, and createdBy/updatedBy when available.

Optionally, document objects can also include a status and locale property if Draft & Publish and Internationalization are enabled for the content-type.

Method overview#

Each section below documents the parameters and examples for a specific method:

MethodPurpose
findOne()Fetch a document by documentId, optionally scoping to a locale or status.
findFirst()Return the first document that matches filters.
findMany()List documents with filters, sorting, and pagination.
create()Create a document, optionally targeting a locale.
update()Update a document by documentId.
delete()Delete a document or a specific locale version.
publish()Publish the draft version of a document.
unpublish()Move a published document back to draft.
discardDraft()Drop draft data and keep only the published version.
count()Count how many documents match the parameters.

findOne()#

Find a document matching the passed documentId and parameters.

Syntax: findOne(parameters: Params) => Document

Parameters#

ParameterDescriptionDefaultType
documentIdDocument idID
localeLocale of the document to find.Default localeString or undefined
statusIf Draft & Publish is enabled for the content-type:
Publication status, can be:
  • 'published' to find only published documents
  • 'draft' to find only draft documents
'draft''published' or 'draft'
fieldsSelect fields to returnAll fields
(except those not populated by default)
Object
populatePopulate results with additional fields.nullObject

Example#

If only a documentId is passed without any other parameters, findOne() returns the draft version of a document in the default locale:

await strapi.documents('api::restaurant.restaurant').findOne({
  documentId: 'a1b2c3d4e5f6g7h8i9j0klm'
})
{
  documentId: "a1b2c3d4e5f6g7h8i9j0klm",
  name: "Biscotte Restaurant",
  publishedAt: null, // draft version (default)
  locale: "en", // default locale
  // …
}

The findOne() method returns the matching document if found, otherwise returns null.

findFirst()#

Find the first document matching the parameters.

Syntax: findFirst(parameters: Params) => Document

Parameters#

ParameterDescriptionDefaultType
localeLocale of the documents to find.Default localeString or undefined
statusIf Draft & Publish is enabled for the content-type:
Publication status, can be:
  • 'published' to find only published documents
  • 'draft' to find only draft documents
'draft''published' or 'draft'
filtersFilters to usenullObject
fieldsSelect fields to returnAll fields
(except those not populate by default)
Object
populatePopulate results with additional fields.nullObject

Examples#


Generic example#

By default, findFirst() returns the draft version, in the default locale, of the first document for the passed unique identifier (collection type id or single type id):

await strapi.documents('api::restaurant.restaurant').findFirst()
{
  documentId: "a1b2c3d4e5f6g7h8i9j0klm",
  name: "Restaurant Biscotte",
  publishedAt: null,
  locale: "en"
  // …
}
Find the first document matching parameters#

Pass some parameters to findFirst() to return the first document matching them.

If no locale or status parameters are passed, results return the draft version for the default locale:

await strapi.documents('api::restaurant.restaurant').findFirst(
  {
    filters: {
      name: {
        $startsWith: "Pizzeria"
      }
    }
  }
)
{
  documentId: "j9k8l7m6n5o4p3q2r1s0tuv",
  name: "Pizzeria Arrivederci",
  publishedAt: null,
  locale: "en"
  // …
}

findMany()#

Find documents matching the parameters.

Syntax: findMany(parameters: Params) => Document[]

Parameters#

ParameterDescriptionDefaultType
localeLocale of the documents to find.Default localeString or undefined
statusIf Draft & Publish is enabled for the content-type:
Publication status, can be:
  • 'published' to find only published documents
  • 'draft' to find only draft documents
'draft''published' or 'draft'
filtersFilters to usenullObject
fieldsSelect fields to returnAll fields
(except those not populate by default)
Object
populatePopulate results with additional fields.nullObject
paginationPaginate results
sortSort results

Examples#


Generic example#

When no parameter is passed, findMany() returns the draft version in the default locale for each document:

await strapi.documents('api::restaurant.restaurant').findMany()
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant",
    publishedAt: null, // draft version (default)
    locale: "en" // default locale
    // …
  },
  {
    documentId: "j9k8l7m6n5o4p3q2r1s0tuv",
    name: "Pizzeria Arrivederci",
    publishedAt: null,
    locale: "en"
    // …
  },
]
Find documents matching parameters#

Available filters are detailed in the filters page of the Document Service API reference.

If no locale or status parameters are passed, results return the draft version for the default locale:

await strapi.documents('api::restaurant.restaurant').findMany(
  {
    filters: { 
      name: {
        $startsWith: 'Pizzeria'
      }
    }
  }
)
[
  {
    documentId: "j9k8l7m6n5o4p3q2r1s0tuv",
    name: "Pizzeria Arrivederci",
    locale: "en", // default locale
    publishedAt: null, // draft version (default)
    // …
  }, 
  // …
]

create()#

Creates a drafted document and returns it.

Pass fields for the content to create in a data object.

Syntax: create(parameters: Params) => Document

Parameters#

ParameterDescriptionDefaultType
localeLocale of the documents to create.Default localeString or undefined
fieldsSelect fields to returnAll fields
(except those not populated by default)
Object
statusIf Draft & Publish is enabled for the content-type:
Can be set to 'published' to automatically publish the draft version of a document while creating it
-'published'
populatePopulate results with additional fields.nullObject

Example#

If no locale parameter is passed, create() creates the draft version of the document for the default locale:

await strapi.documents('api::restaurant.restaurant').create({
  data: {
    name: 'Restaurant B'
  }
})
{
  documentId: "ln1gkzs6ojl9d707xn6v86mw",
  name: "Restaurant B",
  publishedAt: null,
  locale: "en",
}

update()#

Updates document versions and returns them.

Syntax: update(parameters: Params) => Promise<Document>

Parameters#

ParameterDescriptionDefaultType
documentIdDocument idID
localeLocale of the document to update.Default localeString or null
filtersFilters to usenullObject
fieldsSelect fields to returnAll fields
(except those not populate by default)
Object
statusIf Draft & Publish is enabled for the content-type:
Can be set to 'published' to automatically publish the draft version of a document while updating it
-'published'
populatePopulate results with additional fields.nullObject

It's not recommended to update repeatable components with the Document Service API (see the related breaking change entry for more details).

Example#

If no locale parameter is passed, update() updates the document for the default locale:

await strapi.documents('api::restaurant.restaurant').update({ 
    documentId: 'a1b2c3d4e5f6g7h8i9j0klm',
    data: { name: "New restaurant name" }
})
{
  documentId: 'a1b2c3d4e5f6g7h8i9j0klm',
  name: "New restaurant name",
  locale: "en",
  publishedAt: null, // draft
  // …
}

delete()#

Deletes one document, or a specific locale of it.

Syntax: delete(parameters: Params): Promise<{ documentId: ID, entries: Number }>

Parameters#

ParameterDescriptionDefaultType
documentIdDocument idID
localeLocale version of the document to delete.null
(deletes only the default locale)
String, '*', or null
filtersFilters to usenullObject
fieldsSelect fields to returnAll fields
(except those not populate by default)
Object
populatePopulate results with additional fields.nullObject

Example#

If no locale parameter is passed, delete() only deletes the default locale version of a document. This deletes both the draft and published versions:

await strapi.documents('api::restaurant.restaurant').delete({
  documentId: 'a1b2c3d4e5f6g7h8i9j0klm', // documentId,
})
{
  documentId: "a1b2c3d4e5f6g7h8i9j0klm",
  entries: [
    {
      "documentId": "a1b2c3d4e5f6g7h8i9j0klm",
      "name": "Biscotte Restaurant",
      "publishedAt": "2024-03-14T18:30:48.870Z",
      "locale": "en"
      // …
    }
  ]
}

publish()#

Publishes one or multiple locales of a document.

This method is only available if Draft & Publish is enabled on the content-type.

Syntax: publish(parameters: Params): Promise<{ documentId: ID, entries: Number }>

Parameters#

ParameterDescriptionDefaultType
documentIdDocument idID
localeLocale of the documents to publish.Only the default localeString, '*', or null
filtersFilters to usenullObject
fieldsSelect fields to returnAll fields
(except those not populate by default)
Object
populatePopulate results with additional fields.nullObject

Example#

If no locale parameter is passed, publish() only publishes the default locale version of the document:

await strapi.documents('api::restaurant.restaurant').publish({
  documentId: 'a1b2c3d4e5f6g7h8i9j0klm',
});
{
  documentId: "a1b2c3d4e5f6g7h8i9j0klm",
  entries: [
    {
      "documentId": "a1b2c3d4e5f6g7h8i9j0klm",
      "name": "Biscotte Restaurant",
      "publishedAt": "2024-03-14T18:30:48.870Z",
      "locale": "en"
      // …
    }
  ]
}

unpublish()#

Unpublishes one or all locale versions of a document, and returns how many locale versions were unpublished.

This method is only available if Draft & Publish is enabled on the content-type.

Syntax: unpublish(parameters: Params): Promise<{ documentId: ID, entries: Number }>

Parameters#

ParameterDescriptionDefaultType
documentIdDocument idID
localeLocale of the documents to unpublish.Only the default localeString, '*', or null
filtersFilters to usenullObject
fieldsSelect fields to returnAll fields
(except those not populate by default)
Object
populatePopulate results with additional fields.nullObject

Example#

If no locale parameter is passed, unpublish() only unpublishes the default locale version of the document:

await strapi.documents('api::restaurant.restaurant').unpublish({
  documentId: 'a1b2c3d4e5f6g7h8i9j0klm' 
});
{
  documentId: "lviw819d5htwvga8s3kovdij",
  entries: [
    {
      documentId: "lviw819d5htwvga8s3kovdij",
      name: "Biscotte Restaurant",
      publishedAt: null,
      locale: "en"
      // …
    }
  ]
}

discardDraft()#

Discards draft data and overrides it with the published version.

This method is only available if Draft & Publish is enabled on the content-type.

Syntax: discardDraft(parameters: Params): Promise<{ documentId: ID, entries: Number }>

Parameters#

ParameterDescriptionDefaultType
documentIdDocument idID
localeLocale of the documents to discard.Only the default locale.String, '*', or null
filtersFilters to usenullObject
fieldsSelect fields to returnAll fields
(except those not populate by default)
Object
populatePopulate results with additional fields.nullObject

Example#

If no locale parameter is passed, discardDraft() discards draft data and overrides it with the published version only for the default locale:

strapi.documents.discardDraft({
  documentId: 'a1b2c3d4e5f6g7h8i9j0klm', 
});
{
  documentId: "lviw819d5htwvga8s3kovdij",
  entries: [
    {
      documentId: "lviw819d5htwvga8s3kovdij",
      name: "Biscotte Restaurant",
      publishedAt: null,
      locale: "en"
      // …
    }
  ]
}

count()#

Count the number of documents that match the provided parameters.

Syntax: count(parameters: Params) => number

Parameters#

ParameterDescriptionDefaultType
localeLocale of the documents to countDefault localeString or null
statusIf Draft & Publish is enabled for the content-type:
Publication status, can be:
  • 'published' to find only published documents
  • 'draft' to find draft documents (will return all documents)
'draft''published' or 'draft'
filtersFilters to usenullObject

Examples#


Generic example#

If no parameter is passed, the count() method the total number of documents for the default locale:

await strapi.documents('api::restaurant.restaurant').count()
Count published documents#

To count only published documents, pass status: 'published' along with other parameters to the count() method.

If no locale parameter is passed, documents are counted for the default locale.

strapi.documents('api::restaurant.restaurant').count({ status: 'published' })
Count documents with filters#

Any filters can be passed to the count() method.

If no locale and no status parameter is passed, draft documents (which is the total of available documents for the locale since even published documents are counted as having a draft version) are counted only for the default locale:

/**
 * Count number of draft documents (default if status is omitted) 
 * in English (default locale) 
 * whose name starts with 'Pizzeria'
 */
strapi.documents('api::restaurant.restaurant').count({ filters: { name: { $startsWith: "Pizzeria" }}})`