Skip to main content
When you need to remove thousands or millions of documents from an index, deleting them one at a time is impractical. Meilisearch provides batch deletion and filter-based deletion for removing documents efficiently.

Delete by filter

Filter-based deletion removes all documents matching a filter expression. This is the most efficient way to delete large sets of documents when they share a common attribute.
curl \
  -X POST 'MEILISEARCH_URL/indexes/products/documents/delete' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "filter": "status = '\''archived'\''"
  }'
The filter expression supports the same syntax as search filters, including AND, OR, and comparison operators.
Delete-by-filter tasks cannot be autobatched with other task types. Each delete-by-filter operation is processed as its own individual batch. If you are enqueuing many delete-by-filter tasks alongside other write operations, be aware that this may slow down overall task processing.
The attribute used in the filter must be listed in filterableAttributes. If it is not, the request returns an error.

Common filter patterns

Delete by category:
{ "filter": "category = 'discontinued'" }
Delete by date range:
{ "filter": "expires_at < 1704067200" }
Delete with compound conditions:
{ "filter": "status = 'draft' AND updated_at < 1672531200" }

Delete by batch of IDs

When you know the exact document IDs to remove, send them as an array:
curl \
  -X POST 'MEILISEARCH_URL/indexes/products/documents/delete-batch' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '["id1", "id2", "id3", "id4", "id5"]'
For very large ID lists, split them into batches. Each request creates a task, and tasks are processed sequentially:
# Split IDs into chunks and send each as a separate request
# Each batch processes as its own task
for batch_file in id_batch_*.json; do
  curl \
    -X POST 'MEILISEARCH_URL/indexes/products/documents/delete-batch' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer MEILISEARCH_KEY' \
    --data-binary @"$batch_file"
done

Monitor deletion progress

Deletion operations are asynchronous. The response returns a taskUid you can use to track progress:
{
  "taskUid": 128,
  "indexUid": "products",
  "status": "enqueued",
  "type": "documentDeletion"
}
Check the task to see how many documents were deleted:
curl \
  -X GET 'MEILISEARCH_URL/tasks/128' \
  -H 'Authorization: Bearer MEILISEARCH_KEY'
The completed task includes the count of deleted documents:
{
  "uid": 128,
  "status": "succeeded",
  "type": "documentDeletion",
  "details": {
    "providedIds": 0,
    "deletedDocuments": 15234,
    "originalFilter": "status = 'archived'"
  }
}

Choose the right deletion strategy

StrategyBest forExample
Delete by filterRemoving documents that share an attributeRemove all expired listings, delete a product category
Delete by batchRemoving specific documents by IDRemove items flagged by a moderation system
Delete all documentsClearing an index for a full re-importNightly sync from a primary database

Delete all documents

To remove every document in an index while keeping the index settings:
curl \
  -X DELETE 'MEILISEARCH_URL/indexes/products/documents' \
  -H 'Authorization: Bearer MEILISEARCH_KEY'
This is useful when your data pipeline does full replacements. Delete all documents, then re-import the current dataset.

Plan for regular cleanup

If your data has a natural lifecycle (listings expire, events pass, articles are archived), consider adding a timestamp or status field to your documents and making it filterable:
{
  "id": "listing-42",
  "title": "Summer Sale",
  "status": "active",
  "expires_at": 1719792000
}
curl \
  -X PATCH 'MEILISEARCH_URL/indexes/listings/settings' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "filterableAttributes": ["status", "expires_at"]
  }'
Then run periodic cleanup jobs:
# Remove expired listings
curl \
  -X POST 'MEILISEARCH_URL/indexes/listings/documents/delete' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary "{
    \"filter\": \"expires_at < $(date +%s)\"
  }"

Next steps

Add and update documents

Learn about document add, update, and replace operations

Filter expression reference

Full syntax reference for filter expressions

Async operations

Understand how tasks work in Meilisearch