Skip to main content
Meilisearch allows you to edit documents in place using Rhai scripting functions. Instead of fetching documents, modifying them externally, and re-indexing, you write a short function that Meilisearch applies to each matching document.
This feature is experimental. Enable it before use and expect its API to change between releases.

When to use functions

  • Bulk field updates: add, rename, or remove fields across thousands of documents
  • Data normalization: convert strings to uppercase, trim whitespace, reformat dates
  • Computed fields: derive new fields from existing ones (e.g. concatenate firstName and lastName into fullName)
  • Conditional edits: update only documents matching a filter expression

Enable the feature

Send a PATCH request to /experimental-features:
curl \
  -X PATCH 'MEILISEARCH_URL/experimental-features' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "editDocumentsByFunction": true
  }'

Basic usage

Send a POST request to /indexes/{index_uid}/documents/edit with a function parameter containing Rhai code. The function receives each document as doc and can modify its fields directly:
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents/edit' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "function": "doc.title = doc.title.to_upper()"
  }'
This converts the title field to uppercase for every document in the movies index. The operation is asynchronous and returns a task object.

Filter target documents

Use the filter parameter to apply the function only to documents matching a filter expression:
curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents/edit' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "function": "doc.status = \"archived\"",
    "filter": "release_date < \"2000-01-01\""
  }'
This sets status to "archived" only for movies released before the year 2000. The filter parameter uses the same filter expression syntax as search filters. Filtered attributes must be declared in filterableAttributes.

Pass data with context

The context parameter lets you pass external data into your function. Access it through the context variable:
curl \
  -X POST 'MEILISEARCH_URL/indexes/products/documents/edit' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "function": "if context.discounted_ids.contains(doc.id) { doc.price = doc.price * 0.8 }",
    "context": {
      "discounted_ids": [1, 42, 99, 120]
    },
    "filter": "category = \"electronics\""
  }'
This applies a 20% discount to specific products in the electronics category.

Examples

Add a new field

curl \
  -X POST 'MEILISEARCH_URL/indexes/movies/documents/edit' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "function": "doc.title_upper = doc.title.to_upper()"
  }'

Remove a field

curl \
  -X POST 'MEILISEARCH_URL/indexes/users/documents/edit' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "function": "doc.remove(\"temporary_field\")"
  }'

Concatenate fields

curl \
  -X POST 'MEILISEARCH_URL/indexes/contacts/documents/edit' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "function": "doc.full_name = `${doc.first_name} ${doc.last_name}`"
  }'

Conditional logic

curl \
  -X POST 'MEILISEARCH_URL/indexes/products/documents/edit' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "function": "if doc.stock == 0 { doc.availability = \"out_of_stock\" } else { doc.availability = \"in_stock\" }"
  }'

Use context for batch tagging

curl \
  -X POST 'MEILISEARCH_URL/indexes/articles/documents/edit' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer MEILISEARCH_KEY' \
  --data-binary '{
    "function": "doc.tags = context.tags",
    "context": {
      "tags": ["featured", "2026"]
    },
    "filter": "category = \"blog\""
  }'

Rhai language basics

Rhai is a lightweight scripting language. Here are the most common operations for document editing:
OperationSyntax
Set a fielddoc.field = value
String interpolationdoc.field = `Hello ${doc.name}`
Uppercase / lowercasedoc.field.to_upper(), doc.field.to_lower()
Remove a fielddoc.remove("field")
Conditionalsif condition { ... } else { ... }
Access contextcontext.key
Check if array containsarray.contains(value)
String concatenation"hello" + " " + "world"
Math operationsdoc.price * 0.9, doc.count + 1
For the full language reference, see the Rhai Book.

Important considerations

  • Edit-by-function is an asynchronous operation. It returns a task that you can monitor like any other indexing task.
  • The function runs on every document matching the filter (or all documents if no filter is provided). Test on a small subset first using a restrictive filter.
  • Edit-by-function tasks cannot be autobatched with other task types. Each edit operation runs as its own batch.
  • If the function contains a syntax error or runtime error, the task will fail. Check the task’s error field for details.
  • Editing documents triggers a reindex of the modified documents.

Next steps

Filter expression syntax

Learn the full filter syntax for targeting documents.

Rhai language reference

Explore the complete Rhai scripting language documentation.

Monitor tasks

Track the progress of your edit-by-function operations.

Add and update documents

Other ways to modify documents in Meilisearch.