Skip to main content
Convex provides built-in full-text search capabilities through search indexes. Search queries automatically rank results by relevance and support filtering on additional fields.

Search indexes

Define search indexes in your schema to enable full-text search:
A search index requires:
string
The field to perform full-text search on. Must be a string field.
string[]
Additional fields to filter on using equality filters. These can be any Convex value type.
Use .withSearchIndex() to perform full-text search queries:

Search filter builder

The SearchFilterBuilder is provided to construct search queries: Search for terms in the indexed field:
string
The name of the field to search in. Must match the index’s searchField.
string
The query text to search for.
How search works:
  • Returns results where any word of the query appears in the field
  • Results are ranked by relevance considering:
    • How many words in the query appear in the text?
    • How many times do they appear?
    • How long is the text field?

eq (equality filter)

Restrict search results to documents where a filter field equals a value:
string
The name of the field to compare. Must be listed in the search index’s filterFields.
any
The value to compare against. Type must match the field type.
You can chain multiple .eq() calls:

Search results

Search queries return documents in relevance order - the most relevant results appear first. The relevance algorithm considers:
  1. Term frequency - How often query words appear in the document
  2. Document length - Shorter documents with matches rank higher
  3. Coverage - Documents matching more query words rank higher

Taking results

Use .take() to limit results:

Pagination

Search supports pagination for better performance:

Common patterns

Search with category filter

Search with multiple filters

Search across multiple fields

Create separate indexes for different fields and combine results:

Empty search query

Return all documents (filtered) when search query is empty:

Search best practices

  • Define indexes in schema - Search indexes must be defined in convex/schema.ts before use.
  • Limit results with .take() - Don’t use .collect() on search queries, as result sets can be large.
  • Use filter fields - Add filterFields to search indexes for common filters like category or author.
  • Consider multiple indexes - Create separate search indexes for different fields (title, body, etc.).
  • Results are already ordered - Search results come in relevance order, don’t apply additional .order().
  • Prefer search over .filter() for text - Full-text search is much more efficient than filtering with string contains.
  • Handle empty queries - Decide whether empty search strings should return all results or none.

Limitations

  • One search per query - You can only use .withSearchIndex() once per query. To search multiple fields, run separate queries and combine results.
  • Equality filters only - Search indexes only support .eq() filters, not range queries or other comparisons.
  • No ordering - Results are always in relevance order. You cannot apply .order() to search results.
  • Filter fields must be in index - You can only filter on fields listed in the index’s filterFields array.

When to use search vs regular indexes

Use search indexes when:
  • Searching for words or phrases in text content
  • You want relevance-ranked results
  • Users type free-form search queries
Use regular indexes when:
  • Filtering by exact values (IDs, enums, booleans)
  • Range queries (dates, numbers)
  • You need specific ordering (newest first, alphabetical)
  • Querying structured data, not text content