Skip to main content
Meilisearch provides three document operations: add or replace, add or update, and delete. This guide explains the difference between each operation and when to use them.

Add or replace documents

Use POST /indexes/{index_uid}/documents to add new documents or replace existing ones. If a document with the same primary key already exists, Meilisearch replaces the entire document with the new version.
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents' \
  -H 'Content-Type: application/json' \
  --data-binary '[
    {
      "id": 287947,
      "title": "Shazam",
      "poster": "https://image.tmdb.org/t/p/w1280/xnopI5Xtky18MPhK40cZAGAOVeV.jpg",
      "overview": "A boy is given the ability to become an adult superhero in times of need with a single magic word.",
      "release_date": "2019-03-23"
    }
  ]'
This operation is best when you have complete document objects and want to ensure the stored version matches exactly what you send.
When replacing a document, any fields present in the old version but missing from the new version are removed. Always include all fields you want to keep.

Example

Suppose your index contains this document:
{
  "id": 287947,
  "title": "Shazam",
  "overview": "A boy becomes a superhero.",
  "genres": ["Action", "Comedy"]
}
If you send a POST request with:
{
  "id": 287947,
  "title": "Shazam!",
  "overview": "A boy is given the ability to become an adult superhero."
}
The stored document becomes:
{
  "id": 287947,
  "title": "Shazam!",
  "overview": "A boy is given the ability to become an adult superhero."
}
The genres field is gone because it was not included in the replacement.

Add or update documents

Use PUT /indexes/{index_uid}/documents to add new documents or partially update existing ones. If a document with the same primary key already exists, Meilisearch merges the new fields into the existing document. Fields not included in the update remain unchanged.
curl \
  -X PUT 'MEILISEARCH_URL/indexes/movies/documents' \
  -H 'Content-Type: application/json' \
  --data-binary '[
    {
      "id": 287947,
      "title": "Shazam ⚡️",
      "genres": "comedy"
    }
  ]'
This operation is ideal when you only need to change specific fields without resending the entire document.

Example

Starting with the same document:
{
  "id": 287947,
  "title": "Shazam",
  "overview": "A boy becomes a superhero.",
  "genres": ["Action", "Comedy"]
}
If you send a PUT request with:
{
  "id": 287947,
  "title": "Shazam ⚡️",
  "genres": "comedy"
}
The stored document becomes:
{
  "id": 287947,
  "title": "Shazam ⚡️",
  "overview": "A boy becomes a superhero.",
  "genres": "comedy"
}
The overview field is preserved because the update only touched title and genres.

Delete documents

Use DELETE /indexes/{index_uid}/documents/{document_id} to remove a single document by its primary key:
curl \
  -X DELETE 'MEILISEARCH_URL/indexes/movies/documents/25684'
Meilisearch also supports batch deletion and deletion by filter:
  • Delete by batch: send a POST /indexes/{index_uid}/documents/delete-batch request with an array of document IDs
  • Delete by filter: send a POST /indexes/{index_uid}/documents/delete request with a filter expression to remove all matching documents

Choosing the right operation

OperationHTTP methodBehaviorUse when
Add or replacePOSTReplaces entire documentYou have complete documents and want exact control
Add or updatePUTMerges fields into existing documentYou only need to change specific fields
DeleteDELETERemoves document entirelyYou need to remove documents from the index

Batch operations

All three operations support sending multiple documents in a single request. Send an array of documents in the request body:
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents' \
  -H 'Content-Type: application/json' \
  --data-binary '[
    { "id": 1, "title": "Movie One" },
    { "id": 2, "title": "Movie Two" },
    { "id": 3, "title": "Movie Three" }
  ]'
Batch operations are processed as a single task. Meilisearch handles large batches efficiently, so prefer sending documents in bulk rather than one at a time.

Update without creating new documents

By default, both POST and PUT document operations create new documents if no document with the given primary key exists. To change this behavior, add the skipCreation=true query parameter to your request. When enabled, Meilisearch silently ignores any documents whose primary key does not match an existing document in the index.
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents?skipCreation=true' \
  -H 'Content-Type: application/json' \
  --data-binary '[
    { "id": 1, "title": "Updated Title" },
    { "id": 99999, "title": "This document does not exist" }
  ]'
In this example, only document 1 is updated. Document 99999 is ignored because it does not already exist in the index. This is useful when you want to safely update fields for existing documents without accidentally creating incomplete records.

Retrieve multiple documents by ID

Use POST /indexes/{index_uid}/documents/fetch to retrieve specific documents by their primary keys:
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents/fetch' \
  -H 'Content-Type: application/json' \
  --data-binary '{
    "ids": ["id1", "id2", "id3"]
  }'
Meilisearch returns the matching documents in the results array. Note that documents are not returned in the order you queried them, and non-existent IDs are silently ignored.
Prefer POST /indexes/{index_uid}/documents/fetch over GET /indexes/{index_uid}/documents. The GET variant is discouraged unless you have a specific reason to use it (for example, to take advantage of HTTP caching at the proxy or CDN level). The GET route accepts fewer parameters and only supports string filter expressions, while the POST route accepts the richer JSON body used throughout this guide.

Filter the documents you fetch

You can pass a filter expression to POST /indexes/{index_uid}/documents/fetch to retrieve only documents that match a condition:
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents/fetch' \
  -H 'Content-Type: application/json' \
  --data-binary '{
    "filter": "genres = Action AND rating > 8"
  }'
Any attribute you reference in a document filter must first be declared in the index’s filterableAttributes setting. This rule is the same as for search filters and is specific to the documents endpoint when filtering the documents you retrieve or delete.

Supported content types

By default, Meilisearch expects a JSON array in the request body and the Content-Type: application/json header. The documents endpoint also accepts NDJSON (application/x-ndjson) and CSV (text/csv) payloads when you set the matching header.
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents' \
  -H 'Content-Type: text/csv' \
  --data-binary @movies.csv
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents' \
  -H 'Content-Type: application/x-ndjson' \
  --data-binary @movies.ndjson
When uploading CSV data, you can override the default comma separator with the csvDelimiter query parameter (for example, ?csvDelimiter=;).
csvDelimiter is only valid when the request uses Content-Type: text/csv. Passing it alongside a JSON or NDJSON payload returns an error.

Next steps

Documents API reference

Full API reference for document operations

Indexing overview

Learn more about how indexing works in Meilisearch

Monitor tasks

Track the status of your document operations