Connect a vector store¶
Three steps for any backend: install its extra (sqlite needs none — it
ships with the core install), pick one key in config.yaml, put its
connection secret in .env. Indexes, collections, tables, and search
schemas are all created automatically on first ingest. All eight
connectors deliver hybrid search;
switching stores never changes your code.
vector_store: sqlite # or any tab below
If you select a store whose SDK isn't installed, the error names the exact
extra: pip install "ingestlib[qdrant]".
Prefer compose over the per-tab docker run commands? The repo's
infra/docker-compose.yml
starts any backend with one profile —
docker compose -f infra/docker-compose.yml --profile qdrant up -d —
with ports matching the tabs below, and encodes the startup gotchas
(pg18 volume layout, mongodb's dual mounts, Milvus's companions).
The default. One local file, no server, no keys — sqlite-vec for dense KNN, FTS5 BM25 for lexical, fused with RRF.
vector_store: sqlite
# sqlite:
# path: ingestlib.db # relative paths anchor beside config.yaml
Nothing to install or run. Best single-machine choice.
Serverless, fully managed. Two indexes (dense + hosted sparse model) are created on first use.
uv add "ingestlib[pinecone]"
vector_store: pinecone
# .env — key from https://app.pinecone.io → API Keys
PINECONE_API_KEY=…
Local docker or Qdrant Cloud. Dense + BM25 sparse on one collection, fused server-side.
uv add "ingestlib[qdrant]"
vector_store: qdrant
docker run -p 6333:6333 qdrant/qdrant
# .env
QDRANT_URL=http://localhost:6333
QDRANT_API_KEY= # cloud only
The Postgres you already run — HNSW cosine + built-in full-text over a generated tsvector. The extension is enabled and the table created automatically.
uv add "ingestlib[pgvector]"
vector_store: pgvector
docker run -p 5432:5432 -e POSTGRES_PASSWORD=pw pgvector/pgvector:pg18
# .env
PGVECTOR_URL=postgresql://postgres:pw@localhost:5432/postgres
Works with RDS, Supabase, Neon — anywhere the extension ships.
Atlas Vector Search + Atlas Search (true BM25). Atlas any tier, the atlas-local docker image, or self-managed 8.2+ with mongot.
uv add "ingestlib[mongodb]"
vector_store: mongodb
docker run -p 27017:27017 mongodb/mongodb-atlas-local
# .env
MONGODB_URL=mongodb://localhost:27017/?directConnection=true
Search indexes sync a few seconds behind writes — ingestion is unaffected; only write-then-query-immediately notices.
Dense ANN + server-computed BM25, fused server-side. Local standalone docker or Zilliz Cloud.
uv add "ingestlib[milvus]"
vector_store: milvus
# .env
MILVUS_URL=http://localhost:19530
MILVUS_TOKEN= # Zilliz Cloud only
faiss k-NN + Lucene BM25. An Amazon OpenSearch domain — requests are
SigV4-signed with your configured aws.profile, no separate key — or
a local server.
uv add "ingestlib[opensearch]"
vector_store: opensearch
docker run -p 9200:9200 -e discovery.type=single-node \
-e DISABLE_SECURITY_PLUGIN=true opensearchproject/opensearch
# .env
OPENSEARCH_URL=http://localhost:9200
For a real Amazon domain, the repo ships a CloudFormation template
for the cheapest k-NN-capable configuration (~$0.10/hour, delete
when idle):
infra/opensearch.yaml.
HNSW dense + native BM25, fused server-side in one hybrid call. Local docker (publish both ports — the client speaks gRPC too) or Weaviate Cloud.
uv add "ingestlib[weaviate]"
vector_store: weaviate
docker run -p 8080:8080 -p 50051:50051 cr.weaviate.io/semitechnologies/weaviate:latest
# .env
WEAVIATE_URL=http://localhost:8080
WEAVIATE_API_KEY= # cloud only
Verify¶
uv run ingestlib doctor # includes a reachability check for the selected store
Behaviors shared by every connector¶
- Created on first use — no manual index/collection/table setup, and nothing is created on the read path
- Idempotent re-ingestion — same document overwrites in place; a re-parse with fewer chunks prunes the leftovers
- Namespaces and filters work identically everywhere
- Index/collection/table names are configurable per backend — see the configuration reference
- Only the selected connector's SDK is ever used at runtime
Migrating between stores¶
Moving stores is a rebuild, not an export: change vector_store, then run
backfill() (or
ingestlib backfill), which re-embeds every document straight from its
stored split artifact — no re-parse — into the new connector.