All benchmarks

Meilisearch app benchmark

Build storefront search, curation tools, and admin apps using the Meilisearch search engine. Tasks and sources

2026-09-27 · 13 tasks × 2 setups × 2 runs · Pass: browser-tested app, App Grade B or better

0%20%40%60%80%100%pass rateopencode · gpt-5.6-luna (no-web) · 3/26 passed · 11.5% · 95% task-clustered bootstrap: 0%–30.8% · $0.206 per pass · 4.5 min median run11.5%gpt-5.6-lunaOpenCodegpt-5.6-lunaOpenCodeopencode · gpt-5.6-terra (no-web) · 2/26 passed · 7.7% · 95% task-clustered bootstrap: 0%–19.2% · $3.00 per pass · 4.4 min median run7.7%gpt-5.6-terraOpenCodegpt-5.6-terraOpenCode
0%20%40%60%80%100%pass rateopencode · gpt-5.6-luna (no-web) · 3/26 passed · 11.5% · 95% task-clustered bootstrap: 0%–30.8% · $0.206 per pass · 4.5 min median run11.5%gpt-5.6-lunaOpenCodegpt-5.6-lunaOpenCodeopencode · gpt-5.6-terra (no-web) · 2/26 passed · 7.7% · 95% task-clustered bootstrap: 0%–19.2% · $3.00 per pass · 4.4 min median run7.7%gpt-5.6-terraOpenCodegpt-5.6-terraOpenCode
Pass rate by setup
SetupPassedAttemptsPass rateIntervalTiersCost per passCost basisMedian run
opencode · gpt-5.6-luna (no-web)32612%0%–31% (95% task-clustered bootstrap, 26 attempts)3B 2C 21F$0.206receipts, 490 receipts4.5 min
opencode · gpt-5.6-terra (no-web)2268%0%–19% (95% task-clustered bootstrap, 26 attempts)2B 4C 20F$3.00receipts, 447 receipts4.4 min
Pass rate and cost per pass
SetupPass ratePassedIntervalCost per passCost basisOn frontier
opencode · gpt-5.6-luna (no-web)12%3/260%–31% (95% task-clustered bootstrap, 26 attempts)$0.206receiptsnot computed
opencode · gpt-5.6-terra (no-web)8%2/260%–19% (95% task-clustered bootstrap, 26 attempts)$3.00receiptsnot computed
Task by setup
Taskopencode · gpt-5.6-luna (no-web)opencode · gpt-5.6-terra (no-web)
T010/2 · 2F · $0.0490/2 · 2F · $0.394
T020/2 · 1C 1F · $0.0480/2 · 1C 1F · $0.384
T030/2 · 2F · $0.0430/2 · 2F · $0.381
T040/2 · 2F · $0.0390/2 · 2F · $0.448
T052/2 · 2B · $0.0431/2 · 1B 1F · $0.415
T061/2 · 1B 1F · $0.0530/2 · 2F · $0.483
T070/2 · 2F · $0.0410/2 · 2F · $0.438
T080/2 · 2F · $0.0450/2 · 2F · $0.407
T090/2 · 1C 1F · $0.0510/2 · 2C · $0.440
T100/2 · 2F · $0.0551/2 · 1B 1F · $0.685
T110/2 · 2F · $0.0400/2 · 2F · $0.382
T120/2 · 2F · $0.0540/2 · 1C 1F · $0.507
T130/2 · 2F · $0.0570/2 · 2F · $0.644

Task prompts

Tangle’s VerticalBench generated these app-building tasks from the search engine’s documentation and release notes. The prompts and their sources are below.

T01 · Storefront search curation

Build a Meilisearch-powered storefront curation page. A merchandiser opens the page and applies two curation rules to a product catalog: one that lowers out-of-stock products in search results and one that removes discontinued products from results entirely. After applying the rules, the merchandiser searches the catalog, and the page renders the hit list plus, for each hit, a breakdown showing which curation rule was applied and how strongly. The rules are Meilisearch search rules (the experimental `dynamicSearchRules` feature): the page must create them over the search-rules API and run searches with ranking score details enabled so the applied rule and its strength are visible in the response. The app must call Meilisearch only from server-side code, using the MEILISEARCH_URL and MEILISEARCH_KEY environment variables (the key is the only credential and carries only the permissions this task needs).

T02 · Import payload inspector

Build a single-page upload-monitor for a Meilisearch instance. The page lets an operator do a bulk import into a Meilisearch index and immediately inspect exactly what document payload was submitted for that import task. The operator types a title prefix and a document count, clicks Import, and the app bulk-adds that many generated documents to an index named `movies`; then a View payload action on the resulting task streams back the raw documents that were sent and displays the first 20 lines together with the total line count. The app talks to Meilisearch from server-side code only, using the URL and scoped API key supplied in the MEILISEARCH_URL and MEILISEARCH_KEY environment variables (the key is the only credential available). The task's document payload can only be read back while the task is still enqueued or processing, so the payload must be fetched promptly and is identically the records the app itself just submitted.

T03 · Federated search with numbered pages

Build a Next.js page where a user can search two existing Meilisearch indexes, 'articles' and 'notes' (each document has a 'title' field), at the same time and see one merged, ranked list of results drawn from both indexes. Show exactly 10 merged results per page, with page-number controls so the user can move between numbered pages through the complete merged result set instead of an infinite-scroll or 'load more' feed, and let them see the total number of matching results and total pages available.

T04 · Federated client search across CRM indexes

Build a client search tool over three Meilisearch indexes: profiles, chats, and tickets. A user types a client's name and sees one merged, ranked result list drawn from all three sources. Every document in all three indexes carries a shared client_name field, plus source-specific fields (profiles: email and role; chats: message; tickets: subject). Because the same client can have a matching record in more than one of the three indexes, a naive merge would show duplicate rows for that client. The merged results list must show at most one row per client, no matter how many of the three indexes hold a matching record for them.

T05 · Meilisearch Field Schema Browser

Build a schema browser page for the Meilisearch 'products' index. The index holds product documents with many attributes (brand, category, color, price, dimensions, and more). Show every field defined on the index, display how many fields exist in total, and let the user step through them in batches of 20 using a next-page control, always reflecting the index's real current schema rather than a cached or guessed list.

T06 · Federated Search Performance Breakdown

Build a Meilisearch-powered page where a user runs one federated search across two indexes at once, `articles` and `products`, and sees a performance panel that breaks the timing down separately for each of the two underlying queries in that federated search, so they can spot which index's query is the slow one instead of seeing one combined number for the whole request. Seed each index with a couple of documents: `articles` documents have `title` and `body` fields, `products` documents have `name` and `description` fields.

T07 · Meilisearch document template preview

Build a small web app called Template Preview for developers who write Meilisearch document templates. On one page the developer types a document template into a template box and a sample document, written as a JSON object, into a document box, then presses a preview button. The page then shows the template exactly as Meilisearch echoes it back, and the text Meilisearch renders for that template and that document, in two clearly labelled panels. Nothing is indexed: no index, embedder or fragment is set up, the preview works purely on what the developer typed, and the sample document can have any fields (for example title, author, stock). If Meilisearch rejects the template or the document, show its error message on the page instead of a result, and if the document box does not hold a valid JSON object, say so without calling Meilisearch. The Meilisearch instance already has its experimental template-rendering preview feature switched on. The app talks to Meilisearch only from server-side code, and the scoped API key never reaches the browser.

T08 · Meilisearch storage-health page

Build a storage-health page for a Meilisearch operator. The page lists every index on the instance with its uid, its document count, its total size on disk and the part of that size that is actively holding data, both shown as exact whole-number byte counts and taken from the size figures Meilisearch itself reports for each index. Next to them show the reclaimable gap between the two in bytes and as a percentage of the total size, and mark any index whose gap exceeds 30% of its total size with a clear "Compaction candidate" flag; every other index reads as healthy. A filter box above the list narrows it to the indexes whose uid contains the typed text, and a "Check storage" button applies it. The indexes hold documents with id, title and body fields. Meilisearch is called from server-side code only and the key never reaches the browser.

T09 · Movie index maintenance console

Build a maintenance console for the `movies` index of a Meilisearch instance. The index holds movie documents with `id` (the primary key), `title`, `overview` and `genre`, and it has been through many updates and deletions, so its files on disk carry a lot of unused space. The page must show the index's storage health: how many documents it holds, its total size on disk, how much of that size actually holds data, and the gap between the two. A search box lets an operator confirm the catalogue still answers title searches, listing the matching movies. A button compacts the index using Meilisearch's index compaction feature to reclaim the unused disk space. After the operator clicks it, the page follows the maintenance job through the instance's task queue until it finishes, shows the job's final status exactly as Meilisearch reports it, and refreshes the storage figures so the operator can compare the size before and after. Show a clear error message if the job fails or the instance cannot be reached.

T10 · Movie cast cards from related indexes

Build a small movie cast browser on Meilisearch foreign keys (document relations). Meilisearch already holds two indexes and the instance already has the foreign keys feature switched on (it is experimental and off by default elsewhere). The `actors` index has documents with `id`, `name` and `born` (birth year). The `movies` index has documents with `id`, `title` and `actors`, where `actors` is a list of actor ids. Movie documents store only actor ids and must stay that way: never write to the movies documents and never copy actor details into them. Nothing has related the two indexes yet, so the app itself must set that relation up before it relies on it. Home page: a search box and a search button. Searching a movie title shows one card per matching movie with its title and its whole cast, each cast entry showing the actor's name and birth year. The cast for all cards must come from the movie search itself, resolved by Meilisearch from the actors index, with no per-actor lookups by the app. On the same page add a rename form: a dropdown listing every actor by name, a text field for the new name, and a save button. Saving changes that actor's name in the actors index only, keeps the birth year and every other actor field, waits until Meilisearch has applied the change, and refreshes the dropdown. Searching the same title again then shows the new name on every movie card that lists that actor. All Meilisearch calls run on the server; the browser only talks to the app.

T11 · Movie finder by cast birth year and popularity

Build a cast-based movie finder on Meilisearch. The catalogue is already loaded into two indexes and the join between them is already configured: `actors` (documents with id, name, birthYear, popularity) and `movies` (documents with id, title, genres, and an `actors` field that lists the ids of the actors in the film). The page has a birth year input, a minimum popularity input and a Find button. When the visitor presses Find, the page lists the titles of the movies that have at least one cast member born in that year whose popularity is at least the minimum, one title per row, and shows a clear empty message when nothing matches. When the visitor raises the minimum popularity and presses Find again, the list updates and shrinks accordingly; a movie whose popular actors were born in a different year must not appear. The answer comes from Meilisearch itself, using its joins between indexes so the movies are selected by properties of their related actor documents at search time. The app's API key can search the movies and actors indexes.

T12 · Price patch console that only updates existing products

Build a small operator console for a Meilisearch product catalog. The `products` index already exists with primary key `id` and holds five documents, ids 1 to 5, each with `title`, `price` and `stock`. The page lists the current products with those fields. The operator pastes a JSON array of partial updates, for example objects with just an `id` and a `price`, into a text area and presses a send button. These arrays often come from stale spreadsheets, so they can contain ids that are not in the catalog. A checkbox labeled 'Only update existing products', ticked by default, decides what happens to those unknown ids. Ticked: Meilisearch applies the updates only to products that already exist, and the unknown ids never become products. Unticked: the unknown ids are added as new products. Either way, existing products keep every field the update does not mention, so a price patch never loses a title or a stock value. Send the whole array to Meilisearch in one write. Do not read the catalog first to work out which ids to send, because other operators change the catalog at the same time. Wait for the write to finish, then show the document count before and after, which ids now exist in the catalog, and the refreshed product list. Call Meilisearch from server-side code only.

T13 · Labelled product import ledger

Build a small operations page for a Meilisearch index named products (primary key id; every document has an integer id and a name string) that keeps a labelled ledger of writes, using Meilisearch's task custom metadata feature so each write carries a free-text batch label that is stored on its task. The page has three parts. 1. Import. The operator types a batch label into an import label box (free text, for example "supplier-a 2026/09", with spaces and a slash that must reach Meilisearch exactly as typed) and pastes a JSON array of products such as [{"id":1,"name":"Desk lamp"}] into a products box, then presses an import button. The products are added to the products index and the write is tagged with the label. 2. Delete. The operator types one or more product ids separated by commas into a delete ids box and a second label, for example "cleanup-1", into a separate delete label box, then presses a delete button. All listed products are removed in a single write tagged with that label. 3. Ledger. A table lists the 20 most recent tasks on the products index, newest first, with the columns task uid, type, status and label. The label column shows the label as Meilisearch holds it on the task (read back from the task, never remembered by the page) and a dash when the task has no label. A label filter box above the table narrows it to the tasks whose label contains the typed text; the table updates when the operator presses Enter in that box or as they type. After an import or a delete, the ledger shows the new task with its final status once Meilisearch has processed it. All Meilisearch calls happen on the server; the key never reaches the browser.

Comparisons on pass rate
ComparisonPairsMinimum effectIntervalExact interval
opencode · gpt-5.6-terra (no-web) − opencode · gpt-5.6-luna (no-web)26+40 pts−15 pts to +8 pts (95% task-clustered bootstrap, n=26)−11 pts to +9 pts (95% exact McNemar, n=26)