Vector search on documents
Find the documents nearest to a vector (Firestore findNearest): cosine, euclidean or dot product, with filters first and an HNSW index for large collections.
Store an embedding in any document field as an array of numbers, then ask for the documents whose vector is closest to yours — Firestore's findNearest. It runs on pgvector in your project's Postgres, as the caller, so collection rules and row policies decide what comes back. For tables, see vector search on tables; for documents with text and automatic chunking, knowledge bases.
await sov.doc('items/a').set({ kind: 'fruit', embedding: [0.12, 0.88, 0.05] })
const near = await sov.collection('items')
.where('kind', '==', 'fruit') // pre-filter (optional)
.findNearest({ vectorField: 'embedding', queryVector: [0.1, 0.9, 0.0], limit: 5,
distanceMeasure: 'COSINE', distanceThreshold: 0.3 })
.get()
near.docs.forEach((d) => console.log(d.id, d.distance))
// Firestore code works unchanged
import { collection, query, where, findNearest, vector, getDocs } from '@sovaria/sdk/firestore'
await getDocs(findNearest(query(collection(db, 'items'), where('kind', '==', 'fruit')),
{ vectorField: 'embedding', queryVector: vector([0.1, 0.9, 0.0]), limit: 5, distanceMeasure: 'EUCLIDEAN' }))#Options
| Option | What it does |
|---|---|
field / vectorField | The field holding the vector: an array of numbers. Documents whose field isn't an array of exactly the query's length are skipped (never an error). |
vector / queryVector | The query vector, up to 2,000 numbers. |
limit | How many nearest documents to return, up to your plan's docs.vector_max_neighbors. |
distance / distanceMeasure | cosine (default), euclidean or dot_product. Results come back closest first; for dot_product, distance is the inner product and larger is closer. |
where | Filters applied first, the same as in a query (OR groups too). |
distance_threshold | cosine / euclidean: at most this distance. dot_product: at least this product. |
distance_field / distanceResultField | Also write the distance into each result's data under this field. |
collection_group | Search every collection with this id at any depth (see collection groups). |
#Vector indexes
Without an index the search is exact: it compares every matching document. For large collections, create an HNSW vector index for the field, its dimensions and the distance you query with; queries then use it automatically (with filters or row policies, pgvector keeps scanning until it finds limit visible results). It builds in the background without blocking writes and counts toward docs.max_indexes.
curl -s -X POST $URL/api/v1/data/doc/_indexes \
-d '{"collection":"items","vector":{"field":"embedding","dimensions":768,"distance":"cosine"}}' …- pgvector is available on every plan. If it isn't turned on yet, the first search by a project team member enables it; app users get
409 VECTOR_UNAVAILABLEuntil then. - A search slower than your plan's statement timeout returns
504 DEADLINE_EXCEEDEDwith the vector index that would help. - Need embeddings for text? Use your own model, or the project's embedding model through the vectors API.
#Plan limits
| Free | Pro | Ultra | Team | Enterprise | |
|---|---|---|---|---|---|
| Nearest neighbours one document vector search returns | 100 | 500 | 1,000 | 1,000 | 1,000 |
| Document indexes per project | 10 | 100 | 300 | 1,000 | 5,000 |
| Default SQL statement timeout (ms) | 3 s | 8 s | 15 s | 30 s | 60 s |
Asking for more neighbours than your plan allows returns 403 PLAN_LIMIT_REACHED.
#Coming from Firebase or Supabase?
| Platform | What this is called there |
|---|---|
| Firebase | Firestore vector search (findNearest) |
| Supabase | Supabase Vector (pgvector) |
| Sovaria | Vector search on documents |
Moving an existing app? Migrate from Supabase or Firebase imports users (with their passwords), data, files and rules.