Search And Indexes
What this page gives you: a developer workflow for building search features with Anvil. You will learn how to map user intent to index definitions, query shapes, consistency choices, and authorisation-safe results.
Search is a product feature. Users do not care which index family answered the query; they care that results are relevant, fast, current enough, and permitted. Your code should express the user's question clearly enough for Anvil to use the right index and security model.
Start with user intent
Write the product query in plain language:
"Show invoices for this customer from last month."
"Find contracts that mention limitation of liability."
"Show images similar to this one."
"Find artefacts produced by build 1842."
"Search documents I am allowed to see."
Then choose index families.
Use metadata for structured filters:
bucket: documents
prefix: tenants/acme/projects/p-123/
filters:
document_type = contract
status = signed
effective_date >= 2026-01-01
sort: effective_date desc
This should be backed by an index whose fields match the query. If a filter is not indexed, the application should not silently fall back to a bucket scan.
Full text query
Use full text when the user enters words:
query: "payment terms"
fields: title, extracted_text
prefix: tenants/acme/projects/p-123/
filters:
document_type = contract
status != archived
snippet: true
Treat snippets as object exposure. They must be returned only for authorised results.
Vector query
Use vector search when similarity matters:
embedding_model: text-embedding-v3
metric: cosine
dimension: 1536
vector: [0.021, -0.017, ...]
filters:
language = en-GB
limit: 20
The model, metric, and dimension are part of the index contract. A vector generated by one model is not interchangeable with another unless the model provider guarantees it.
Hybrid query
Hybrid search combines signals:
text: "renewal notice"
vector: embedding("contract renewal obligations")
filters:
document_type = contract
status != archived
prefix: tenants/acme/
ranking:
text_weight = 0.55
vector_weight = 0.35
freshness_weight = 0.10
Let Anvil combine and authorize the result set. Do not fetch text results, fetch vector results, merge in memory, and hope consistency and permissions still hold.
Consistency choices
Some screens require fresh results. Others can tolerate short lag. Make the choice explicit.
Examples:
after uploading a document, the UI may wait for the metadata index to include it;
full text extraction may show "indexing" until text is available;
semantic search may show a partial state until embeddings finish;
a permission change may require authorisation-derived indexes to catch up before showing results.
If Anvil reports IndexNotReady, that is not an error to bypass. It is a consistency signal.
Search result design
A good result item should include enough information to render and debug:
title or display metadata;
snippet where requested and authorised;
score components when useful;
index generation or cursor;
request id for diagnostics.
Keep the result tied to source version. If the user opens it, the application can read the same version or deliberately follow the latest head.
What you can build after this page
You should be able to define search features around metadata, full text, vector, and hybrid indexes while preserving authorisation and consistency. Next, use PersonalDB when the application needs local-first database sync rather than object-only workflows.