Vector Stores
A vector store holds documents alongside their embeddings and returns the ones most similar to a query. In Rig they are the storage layer behind RAG: embed your data once, insert it into a store, and query the store at prompt time.
Every integration implements the same two traits, so the code that inserts and queries documents is nearly identical whether you use the built-in in-memory store or a database such as Qdrant, MongoDB or LanceDB. This page covers those shared pieces; the per-store pages cover setup.
Minimal example
Section titled “Minimal example”The in-memory store ships in rig, so it needs no feature and no running database:
use rig::prelude::*;use serde::{Deserialize, Serialize};use rig::providers::openai::{self, OpenAI};
#[derive(Embed, Clone, Serialize, Deserialize, Debug)]struct WordDefinition { id: String, #[embed] definition: String,}
#[tokio::main]async fn main() -> Result<(), anyhow::Error> { let model = OpenAI::from_env()?.embedding(openai::TEXT_EMBEDDING_3_SMALL, None);
let documents = vec![ WordDefinition { id: "doc0".into(), definition: "A flurbo is a green alien.".into() }, WordDefinition { id: "doc1".into(), definition: "A glarb-glarb is an ancient farming tool.".into() }, ];
// Embed each document's `#[embed]` field. let embeddings = EmbeddingsBuilder::new(model.clone()) .documents(documents)? .build() .await?;
// Store the documents and build an index that embeds queries with the same model. let index = InMemoryVectorStore::from_documents(embeddings).index(model);
let req = VectorSearchRequest::builder() .query("What is a flurbo?") .samples(1) .build();
for result in index.top_n::<WordDefinition>(req).await? { println!("{:.3} {}: {}", result.score, result.id, result.document.definition); }
Ok(())}Switching to a database only changes how you build the store; the EmbeddingsBuilder and VectorSearchRequest steps stay the same.
Embedding your documents
Section titled “Embedding your documents”Derive Embed on your type and mark the field (or fields) to embed with #[embed]. EmbeddingsBuilder batches the embedding calls:
use rig::prelude::*;use rig::providers::openai::{self, OpenAI};
#[derive(Embed, Clone, Serialize, Deserialize)]struct Document { id: String, #[embed] content: String,}
let model = OpenAI::from_env()?.embedding(openai::TEXT_EMBEDDING_3_SMALL, None);let docs = vec![Document { id: "doc0".into(), content: "Rig is a Rust library.".into() }];
let embeddings: Vec<(Document, Vec<rig::embeddings::Embedding>)> = EmbeddingsBuilder::new(model) .documents(docs)? .build() .await?;build() returns each document paired with a Vec<Embedding>. A document can carry several embeddings (one per #[embed] field entry, or one per chunk), and stores rank it by its best match. Use .document(doc)? to add one document at a time.
Use the same embedding model to fill a store and to query it. The store’s vector width (when it has one) must match the model’s: model.capabilities().ndims.
See Embeddings for the Embed derive and embedding models.
Core traits
Section titled “Core traits”Both traits live in rig::vector_store.
VectorStoreIndex
Section titled “VectorStoreIndex”The read side: query a store by similarity.
pub trait VectorStoreIndex: Send + Sync { /// The backend's filter type. type Filter: SearchFilter + Send + Sync;
/// The top `samples` documents, most similar first, deserialized as `T`. async fn top_n<T: DeserializeOwned + Send>( &self, req: VectorSearchRequest<Self::Filter>, ) -> Result<Vec<VectorSearchResult<T>>, VectorStoreError>;
/// The same ranking, ids and scores only. async fn top_n_ids( &self, req: VectorSearchRequest<Self::Filter>, ) -> Result<Vec<VectorSearchIdResult>, VectorStoreError>;}
pub struct VectorSearchResult<T> { pub score: f64, // scale and direction follow the backend's metric pub id: String, pub document: T,}InsertDocuments
Section titled “InsertDocuments”The write side: add documents with precomputed embeddings. Pass it the output of EmbeddingsBuilder::build():
pub trait InsertDocuments: Send + Sync { async fn insert_documents<Doc: Serialize + Embed + Send>( &self, documents: Vec<(Doc, Vec<Embedding>)>, ) -> Result<(), VectorStoreError>;}Most database stores implement both traits. The in-memory store is filled through its constructors and add_documents, and the LanceDB index reads a table you populate with LanceDB’s own API.
Querying with VectorSearchRequest
Section titled “Querying with VectorSearchRequest”Every query is a VectorSearchRequest: the query text, the number of results (samples), an optional threshold that drops weak matches, and an optional metadata filter. Searching an index directly shows a full query and its results.
How the threshold compares depends on the backend’s metric; the store pages note where it differs. The default filter type, rig::vector_store::request::Filter, is backend-neutral and is what the in-memory store uses. Database stores have their own filter types with the same SearchFilter methods (eq, gt, lt, and, or) plus backend-specific ones, for example QdrantFilter, LanceDBFilter (SQL predicates) and MongoDbSearchFilter. Name the type on the request, as in VectorSearchRequest::<QdrantFilter>::builder(); a neutral Filter converts to a backend filter with filter.interpret().
Using a store from an agent
Section titled “Using a store from an agent”Every VectorStoreIndex whose filter can be deserialized from JSON is also a tool, so an agent can search it when it decides to:
use rig::prelude::*;use rig::providers::openai::{self, OpenAI};
let client = OpenAI::from_env()?;let index = InMemoryVectorStore::<String>::default() .index(client.embedding(openai::TEXT_EMBEDDING_3_SMALL, None));
let agent = AgentBuilder::new(client.completion(openai::GPT_5_5)) .preamble("Search the knowledge base before answering.") .tool(index) .build();To retrieve context automatically on every prompt instead, use .dynamic_context(samples, index). See RAG.
Errors
Section titled “Errors”Store operations return VectorStoreError: EmbeddingError (the embedding call failed), JsonError (a document didn’t serialize or deserialize), DatastoreError (the backend failed), FilterError (a filter couldn’t be built or translated), MissingIdError, SamplesOutOfRange, and Http / ExternalAPIError for stores reached over HTTP.
Integrations
Section titled “Integrations”The in-memory store is built into rig. Every other store is a companion crate, enabled with a feature on rig and reached through a module of the same name:
[dependencies]rig = { version = "0.44.0", features = ["qdrant"] }| Store | Feature | Main types | Notes |
|---|---|---|---|
| In-memory | none | InMemoryVectorStore, InMemoryVectorIndex | RAM only; brute force or LSH. For development, tests and small datasets. |
| LanceDB | lancedb | rig::lancedb::LanceDbVectorIndex | Embedded columnar store on local disk or S3/GCS/Azure; exact or IVF-PQ search. |
| MongoDB | mongodb | rig::mongodb::MongoDbVectorIndex | Atlas Vector Search. |
| Neo4j | neo4j | rig::neo4j::Neo4jClient, Neo4jVectorIndex | Vector index next to your graph data. |
| Qdrant | qdrant | rig::qdrant::QdrantVectorStore | Dedicated vector database. |
| SurrealDB | surrealdb | rig::surrealdb::SurrealVectorStore | In-memory or remote SurrealDB. |
| SQLite | sqlite | rig::sqlite::SqliteVectorStore, SqliteVectorIndex | Single file, via the sqlite-vec extension; you describe the table with SqliteVectorStoreTable. |
| PostgreSQL | postgres | rig::postgres::PostgresVectorStore | pgvector column with a choice of distance function. |
| Milvus | milvus | rig::milvus::MilvusVectorStore | Milvus v2 HTTP API. |
| ScyllaDB | scylladb | rig::scylladb::ScyllaDbVectorStore | Stores vectors in ScyllaDB and scores them in your process. |
| HelixDB | helixdb | rig::helixdb::HelixDBVectorStore | Through HelixDB’s HTTP client. |
| AWS S3 Vectors | s3vectors | rig::s3vectors::S3VectorsVectorStore | Takes your AWS SDK client. |
| Cloudflare Vectorize | vectorize | rig::vectorize::VectorizeVectorStore | Over Cloudflare’s HTTP API. |
For embeddings that never leave your machine, the fastembed feature adds rig::fastembed, local embedding models that work with every store above. See Local Models.
Next steps
Section titled “Next steps”- RAG: how retrieval fits into an agent.
- Embeddings: the
Embedderive and embedding models. - Build a RAG system: an end-to-end tutorial.
rig::vector_storeon docs.rs
