> ## Documentation Index
> Fetch the complete documentation index at: https://www.meilisearch.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Edit documents with functions

> Use Rhai scripting functions to transform documents directly inside Meilisearch without re-uploading them.

Meilisearch allows you to edit documents in place using [Rhai](https://rhai.rs/book/) scripting functions. Instead of fetching documents, modifying them externally, and re-indexing, you write a short function that Meilisearch applies to each matching document.

> [!NOTE]
>
> 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`:

```bash theme={null}
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:

```bash theme={null}
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:

```bash theme={null}
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](https://www.meilisearch.com/docs/capabilities/filtering_sorting_faceting/advanced/filter_expression_syntax.md) 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:

```bash theme={null}
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

```bash theme={null}
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

```bash theme={null}
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

```bash theme={null}
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

```bash theme={null}
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

```bash theme={null}
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:

| Operation | Syntax |
| - | - |
| Set a field | `doc.field = value` |
| String interpolation | `` doc.field = `Hello ${doc.name}` `` |
| Uppercase / lowercase | `doc.field.to_upper()`, `doc.field.to_lower()` |
| Remove a field | `doc.remove("field")` |
| Conditionals | `if condition { ... } else { ... }` |
| Access context | `context.key` |
| Check if array contains | `array.contains(value)` |
| String concatenation | `"hello" + " " + "world"` |
| Math operations | `doc.price * 0.9`, `doc.count + 1` |

For the full language reference, see the [Rhai Book](https://rhai.rs/book/).

## Important considerations

* Edit-by-function is an **asynchronous operation**. It returns a task that you can [monitor](https://www.meilisearch.com/docs/capabilities/indexing/tasks_and_batches/monitor_tasks.md) 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

> [card] [Filter expression syntax](https://www.meilisearch.com/docs/capabilities/filtering_sorting_faceting/advanced/filter_expression_syntax.md)
>
> Learn the full filter syntax for targeting documents.

> [card] [Rhai language reference](https://rhai.rs/book/)
>
> Explore the complete Rhai scripting language documentation.

> [card] [Monitor tasks](https://www.meilisearch.com/docs/capabilities/indexing/tasks_and_batches/monitor_tasks.md)
>
> Track the progress of your edit-by-function operations.

> [card] [Add and update documents](https://www.meilisearch.com/docs/capabilities/indexing/how_to/add_and_update_documents.md)
>
> Other ways to modify documents in Meilisearch.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.